From 8d7fd6165bf49bb3d50187310f9e8ee97a16fe30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Andr=C3=A9s=20Margffoy=20Tuay?= Date: Mon, 18 May 2020 16:34:57 -0500 Subject: [PATCH 01/10] Update Jedi requirement to 0.17 --- requirements/conda.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements/conda.txt b/requirements/conda.txt index 2e5e4e18f53..3e915de872e 100644 --- a/requirements/conda.txt +++ b/requirements/conda.txt @@ -9,12 +9,12 @@ cloudpickle >=0.5.0 diff-match-patch >=20181111 intervaltree IPython >=4.0 -jedi =0.15.2 +jedi =0.17.0 keyring nbconvert >=4.0 numpydoc >=0.6.0 Paramiko >=2.4.0 -parso =0.5.2 +parso =0.7.0 pexpect >=4.4.0 pickleshare >=0.4 psutil >=5.3 From 7bfb15cfaf64685d6b46d18c8a9b58b36b37a2fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Andr=C3=A9s=20Margffoy=20Tuay?= Date: Mon, 18 May 2020 17:01:10 -0500 Subject: [PATCH 02/10] Update requirements across all files --- binder/environment.yml | 4 ++-- setup.py | 4 ++-- spyder/dependencies.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/binder/environment.yml b/binder/environment.yml index 8ba4bc489a3..b59c87edf45 100644 --- a/binder/environment.yml +++ b/binder/environment.yml @@ -14,12 +14,12 @@ dependencies: - diff-match-patch >=20181111 - intervaltree - ipython >=4.0 -- jedi =0.15.2 +- jedi =0.17.0 - keyring - nbconvert >=4.0 - numpydoc >=0.6.0 - paramiko >=2.4.0 -- parso =0.5.2 +- parso =0.7.0 - pexpect >=4.4.0 - pickleshare >=0.4 - psutil >=5.3 diff --git a/setup.py b/setup.py index 08657702c05..37270680f71 100644 --- a/setup.py +++ b/setup.py @@ -210,7 +210,7 @@ def run(self): 'ipython>=4.0', # This is here until Jedi 0.15+ fixes completions for # Numpy and Pandas - 'jedi==0.15.2', + 'jedi==0.17.0', # Don't require keyring for Python 2 and Linux # because it depends on system packages 'keyring;sys_platform!="linux2"', @@ -218,7 +218,7 @@ def run(self): 'numpydoc>=0.6.0', # Required to get SSH connections to remote kernels 'paramiko>=2.4.0;platform_system=="Windows"', - 'parso==0.5.2', + 'parso==0.7.0', 'pexpect>=4.4.0', 'pickleshare>=0.4', 'psutil>=5.3', diff --git a/spyder/dependencies.py b/spyder/dependencies.py index 8f42fc6bc97..f06804c8760 100644 --- a/spyder/dependencies.py +++ b/spyder/dependencies.py @@ -36,12 +36,12 @@ DIFF_MATCH_PATCH_REQVER = '>=20181111' INTERVALTREE_REQVER = None IPYTHON_REQVER = ">=4.0;<6.0" if PY2 else ">=4.0" -JEDI_REQVER = '=0.15.2' +JEDI_REQVER = '=0.17.0' KEYRING_REQVER = None NBCONVERT_REQVER = '>=4.0' NUMPYDOC_REQVER = '>=0.6.0' PARAMIKO_REQVER = '>=2.4.0' -PARSO_REQVER = '=0.5.2' +PARSO_REQVER = '=0.7.0' PEXPECT_REQVER = '>=4.4.0' PICKLESHARE_REQVER = '>=0.4' PSUTIL_REQVER = '>=5.3' From dbb0398cd7e309e6de7a7740c57a03ecbb26ac11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Andr=C3=A9s=20Margffoy=20Tuay?= Date: Thu, 28 May 2020 17:51:35 -0500 Subject: [PATCH 03/10] Remove previous pyls version --- .../.circleci/config.yml | 60 - .../python-language-server/.coveragerc | 2 - .../python-language-server/.gitattributes | 1 - .../python-language-server/.gitignore | 114 -- external-deps/python-language-server/.gitrepo | 12 - .../python-language-server/.pylintrc | 29 - external-deps/python-language-server/LICENSE | 21 - .../python-language-server/MANIFEST.in | 6 - .../python-language-server/README.rst | 161 -- .../python-language-server/RELEASE.md | 11 - .../python-language-server/appveyor.yml | 32 - .../python-language-server/pyls/__init__.py | 19 - .../python-language-server/pyls/__main__.py | 127 -- .../python-language-server/pyls/_utils.py | 200 -- .../python-language-server/pyls/_version.py | 520 ----- .../pyls/config/__init__.py | 1 - .../pyls/config/config.py | 155 -- .../pyls/config/flake8_conf.py | 48 - .../pyls/config/pycodestyle_conf.py | 30 - .../pyls/config/source.py | 86 - .../python-language-server/pyls/hookspecs.py | 122 -- .../python-language-server/pyls/lsp.py | 78 - .../pyls/plugins/__init__.py | 1 - .../pyls/plugins/autopep8_format.py | 63 - .../pyls/plugins/definition.py | 33 - .../pyls/plugins/flake8_lint.py | 149 -- .../pyls/plugins/folding.py | 203 -- .../pyls/plugins/highlight.py | 24 - .../pyls/plugins/hover.py | 51 - .../pyls/plugins/jedi_completion.py | 187 -- .../pyls/plugins/mccabe_lint.py | 40 - .../pyls/plugins/preload_imports.py | 34 - .../pyls/plugins/pycodestyle_lint.py | 77 - .../pyls/plugins/pydocstyle_lint.py | 119 -- .../pyls/plugins/pyflakes_lint.py | 80 - .../pyls/plugins/pylint_lint.py | 165 -- .../pyls/plugins/references.py | 24 - .../pyls/plugins/rope_completion.py | 107 - .../pyls/plugins/rope_rename.py | 48 - .../pyls/plugins/signature.py | 57 - .../pyls/plugins/symbols.py | 103 - .../pyls/plugins/yapf_format.py | 56 - .../python-language-server/pyls/python_ls.py | 412 ---- .../python-language-server/pyls/uris.py | 129 -- .../python-language-server/pyls/workspace.py | 270 --- .../resources/auto-complete.gif | Bin 55532 -> 0 bytes .../resources/document-format.gif | Bin 66169 -> 0 bytes .../resources/document-symbols.gif | Bin 37353 -> 0 bytes .../resources/goto-definition.gif | Bin 44400 -> 0 bytes .../resources/hover.gif | Bin 36464 -> 0 bytes .../resources/linting.gif | Bin 30013 -> 0 bytes .../resources/references.gif | Bin 109136 -> 0 bytes .../resources/signature-help.gif | Bin 10586 -> 0 bytes .../scripts/circle/pypi.sh | 17 - .../python-language-server/setup.cfg | 18 - external-deps/python-language-server/setup.py | 103 - .../python-language-server/test/__init__.py | 11 - .../python-language-server/test/conftest.py | 11 - .../python-language-server/test/fixtures.py | 52 - .../test/plugins/__init__.py | 0 .../test/plugins/test_autopep8_format.py | 44 - .../test/plugins/test_completion.py | 313 --- .../test/plugins/test_definitions.py | 57 - .../test/plugins/test_flake8_lint.py | 65 - .../test/plugins/test_folding.py | 168 -- .../test/plugins/test_highlight.py | 56 - .../test/plugins/test_hover.py | 73 - .../test/plugins/test_mccabe_lint.py | 37 - .../test/plugins/test_pycodestyle_lint.py | 112 - .../test/plugins/test_pydocstyle_lint.py | 56 - .../test/plugins/test_pyflakes_lint.py | 62 - .../test/plugins/test_pylint_lint.py | 117 -- .../test/plugins/test_references.py | 79 - .../test/plugins/test_signature.py | 94 - .../test/plugins/test_symbols.py | 91 - .../test/plugins/test_yapf_format.py | 58 - .../test/test_document.py | 99 - .../test/test_language_server.py | 103 - .../python-language-server/test/test_uris.py | 50 - .../python-language-server/test/test_utils.py | 103 - .../test/test_workspace.py | 121 -- .../python-language-server/versioneer.py | 1822 ----------------- .../vscode-client/.gitignore | 4 - .../vscode-client/.vscodeignore | 9 - .../vscode-client/License.txt | 11 - .../vscode-client/README.md | 33 - .../vscode-client/ThirdPartyNotices.txt | 31 - .../vscode-client/package.json | 296 --- .../vscode-client/src/extension.ts | 51 - .../vscode-client/tsconfig.json | 13 - .../vscode-client/yarn.lock | 1821 ---------------- 91 files changed, 10528 deletions(-) delete mode 100644 external-deps/python-language-server/.circleci/config.yml delete mode 100644 external-deps/python-language-server/.coveragerc delete mode 100644 external-deps/python-language-server/.gitattributes delete mode 100644 external-deps/python-language-server/.gitignore delete mode 100644 external-deps/python-language-server/.gitrepo delete mode 100644 external-deps/python-language-server/.pylintrc delete mode 100644 external-deps/python-language-server/LICENSE delete mode 100644 external-deps/python-language-server/MANIFEST.in delete mode 100644 external-deps/python-language-server/README.rst delete mode 100644 external-deps/python-language-server/RELEASE.md delete mode 100644 external-deps/python-language-server/appveyor.yml delete mode 100644 external-deps/python-language-server/pyls/__init__.py delete mode 100644 external-deps/python-language-server/pyls/__main__.py delete mode 100644 external-deps/python-language-server/pyls/_utils.py delete mode 100644 external-deps/python-language-server/pyls/_version.py delete mode 100644 external-deps/python-language-server/pyls/config/__init__.py delete mode 100644 external-deps/python-language-server/pyls/config/config.py delete mode 100644 external-deps/python-language-server/pyls/config/flake8_conf.py delete mode 100644 external-deps/python-language-server/pyls/config/pycodestyle_conf.py delete mode 100644 external-deps/python-language-server/pyls/config/source.py delete mode 100644 external-deps/python-language-server/pyls/hookspecs.py delete mode 100644 external-deps/python-language-server/pyls/lsp.py delete mode 100644 external-deps/python-language-server/pyls/plugins/__init__.py delete mode 100644 external-deps/python-language-server/pyls/plugins/autopep8_format.py delete mode 100644 external-deps/python-language-server/pyls/plugins/definition.py delete mode 100644 external-deps/python-language-server/pyls/plugins/flake8_lint.py delete mode 100644 external-deps/python-language-server/pyls/plugins/folding.py delete mode 100644 external-deps/python-language-server/pyls/plugins/highlight.py delete mode 100644 external-deps/python-language-server/pyls/plugins/hover.py delete mode 100644 external-deps/python-language-server/pyls/plugins/jedi_completion.py delete mode 100644 external-deps/python-language-server/pyls/plugins/mccabe_lint.py delete mode 100644 external-deps/python-language-server/pyls/plugins/preload_imports.py delete mode 100644 external-deps/python-language-server/pyls/plugins/pycodestyle_lint.py delete mode 100644 external-deps/python-language-server/pyls/plugins/pydocstyle_lint.py delete mode 100644 external-deps/python-language-server/pyls/plugins/pyflakes_lint.py delete mode 100644 external-deps/python-language-server/pyls/plugins/pylint_lint.py delete mode 100644 external-deps/python-language-server/pyls/plugins/references.py delete mode 100644 external-deps/python-language-server/pyls/plugins/rope_completion.py delete mode 100644 external-deps/python-language-server/pyls/plugins/rope_rename.py delete mode 100644 external-deps/python-language-server/pyls/plugins/signature.py delete mode 100644 external-deps/python-language-server/pyls/plugins/symbols.py delete mode 100644 external-deps/python-language-server/pyls/plugins/yapf_format.py delete mode 100644 external-deps/python-language-server/pyls/python_ls.py delete mode 100644 external-deps/python-language-server/pyls/uris.py delete mode 100644 external-deps/python-language-server/pyls/workspace.py delete mode 100644 external-deps/python-language-server/resources/auto-complete.gif delete mode 100644 external-deps/python-language-server/resources/document-format.gif delete mode 100644 external-deps/python-language-server/resources/document-symbols.gif delete mode 100644 external-deps/python-language-server/resources/goto-definition.gif delete mode 100644 external-deps/python-language-server/resources/hover.gif delete mode 100644 external-deps/python-language-server/resources/linting.gif delete mode 100644 external-deps/python-language-server/resources/references.gif delete mode 100644 external-deps/python-language-server/resources/signature-help.gif delete mode 100755 external-deps/python-language-server/scripts/circle/pypi.sh delete mode 100644 external-deps/python-language-server/setup.cfg delete mode 100755 external-deps/python-language-server/setup.py delete mode 100644 external-deps/python-language-server/test/__init__.py delete mode 100644 external-deps/python-language-server/test/conftest.py delete mode 100644 external-deps/python-language-server/test/fixtures.py delete mode 100644 external-deps/python-language-server/test/plugins/__init__.py delete mode 100644 external-deps/python-language-server/test/plugins/test_autopep8_format.py delete mode 100644 external-deps/python-language-server/test/plugins/test_completion.py delete mode 100644 external-deps/python-language-server/test/plugins/test_definitions.py delete mode 100644 external-deps/python-language-server/test/plugins/test_flake8_lint.py delete mode 100644 external-deps/python-language-server/test/plugins/test_folding.py delete mode 100644 external-deps/python-language-server/test/plugins/test_highlight.py delete mode 100644 external-deps/python-language-server/test/plugins/test_hover.py delete mode 100644 external-deps/python-language-server/test/plugins/test_mccabe_lint.py delete mode 100644 external-deps/python-language-server/test/plugins/test_pycodestyle_lint.py delete mode 100644 external-deps/python-language-server/test/plugins/test_pydocstyle_lint.py delete mode 100644 external-deps/python-language-server/test/plugins/test_pyflakes_lint.py delete mode 100644 external-deps/python-language-server/test/plugins/test_pylint_lint.py delete mode 100644 external-deps/python-language-server/test/plugins/test_references.py delete mode 100644 external-deps/python-language-server/test/plugins/test_signature.py delete mode 100644 external-deps/python-language-server/test/plugins/test_symbols.py delete mode 100644 external-deps/python-language-server/test/plugins/test_yapf_format.py delete mode 100644 external-deps/python-language-server/test/test_document.py delete mode 100644 external-deps/python-language-server/test/test_language_server.py delete mode 100644 external-deps/python-language-server/test/test_uris.py delete mode 100644 external-deps/python-language-server/test/test_utils.py delete mode 100644 external-deps/python-language-server/test/test_workspace.py delete mode 100644 external-deps/python-language-server/versioneer.py delete mode 100644 external-deps/python-language-server/vscode-client/.gitignore delete mode 100644 external-deps/python-language-server/vscode-client/.vscodeignore delete mode 100644 external-deps/python-language-server/vscode-client/License.txt delete mode 100644 external-deps/python-language-server/vscode-client/README.md delete mode 100644 external-deps/python-language-server/vscode-client/ThirdPartyNotices.txt delete mode 100644 external-deps/python-language-server/vscode-client/package.json delete mode 100644 external-deps/python-language-server/vscode-client/src/extension.ts delete mode 100644 external-deps/python-language-server/vscode-client/tsconfig.json delete mode 100644 external-deps/python-language-server/vscode-client/yarn.lock diff --git a/external-deps/python-language-server/.circleci/config.yml b/external-deps/python-language-server/.circleci/config.yml deleted file mode 100644 index 7ec7b8a3fd2..00000000000 --- a/external-deps/python-language-server/.circleci/config.yml +++ /dev/null @@ -1,60 +0,0 @@ -version: 2 - -jobs: - python2-test: - docker: - - image: "python:2.7-stretch" - steps: - - checkout - - run: pip install -e .[all] .[test] - - run: py.test -v test/ - - run: pylint pyls test - - run: pycodestyle pyls test - - run: pyflakes pyls test - - python3-test: - docker: - - image: "python:3.5-stretch" - steps: - - checkout - # To test Jedi environments - - run: python3 -m venv /tmp/pyenv - - run: /tmp/pyenv/bin/python -m pip install loghub - - run: pip install -e .[all] .[test] - - run: py.test -v test/ - - lint: - docker: - - image: "python:2.7-stretch" - steps: - - checkout - - run: pip install -e .[all] .[test] - - run: pylint pyls test - - run: pycodestyle pyls test - - run: pyflakes pyls test - - publish: - docker: - - image: "python:3.5-stretch" - steps: - - checkout - - run: ./scripts/circle/pypi.sh - - -workflows: - version: 2 - build: - jobs: - - python2-test: - filters: { tags: { only: /.*/ } } - - python3-test: - filters: { tags: { only: /.*/ } } - - publish: - filters: - tags: - only: /[0-9]+(\.[0-9]+)+((-(beta|rc)[0-9]{1,2})(\.[0-9])?)?/ - branches: - ignore: /.*/ - requires: - - python2-test - - python3-test diff --git a/external-deps/python-language-server/.coveragerc b/external-deps/python-language-server/.coveragerc deleted file mode 100644 index ba07147bd48..00000000000 --- a/external-deps/python-language-server/.coveragerc +++ /dev/null @@ -1,2 +0,0 @@ -[run] -omit = pyls/_version.py diff --git a/external-deps/python-language-server/.gitattributes b/external-deps/python-language-server/.gitattributes deleted file mode 100644 index 1602f1535a5..00000000000 --- a/external-deps/python-language-server/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -pyls/_version.py export-subst diff --git a/external-deps/python-language-server/.gitignore b/external-deps/python-language-server/.gitignore deleted file mode 100644 index ac609b32350..00000000000 --- a/external-deps/python-language-server/.gitignore +++ /dev/null @@ -1,114 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# IntelliJ -*.iml -*.ipr -*.iws -.idea/ -out/ - -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -env3/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -*.egg-info/ -.installed.cfg -*.egg - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*,cover -.hypothesis/ -pytest.xml -.pytest_cache/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -target/ - -# IPython Notebook -.ipynb_checkpoints - -# pyenv -.python-version - -# celery beat schedule file -celerybeat-schedule - -# dotenv -.env - -# virtualenv -venv/ -ENV/ - -# Spyder project settings -.spyderproject - -# Rope project settings -.ropeproject - -# JavaScript -**/*.vscode/ - -# vim -*.sw[mnopqrs] - -# Idea -.idea/ - -# Merge orig files -*.orig - -# Special files -.DS_Store diff --git a/external-deps/python-language-server/.gitrepo b/external-deps/python-language-server/.gitrepo deleted file mode 100644 index c0079bf129d..00000000000 --- a/external-deps/python-language-server/.gitrepo +++ /dev/null @@ -1,12 +0,0 @@ -; DO NOT EDIT (unless you know what you are doing) -; -; This subdirectory is a git "subrepo", and this file is maintained by the -; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme -; -[subrepo] - remote = https://github.com/palantir/python-language-server.git - branch = develop - commit = fdb8b3dbc5df7d12729d135932bf2264e0883061 - parent = 0798ff6e51f6d1c353b8278469a32adab54b874f - method = merge - cmdver = 0.4.1 diff --git a/external-deps/python-language-server/.pylintrc b/external-deps/python-language-server/.pylintrc deleted file mode 100644 index 29802a2cb6b..00000000000 --- a/external-deps/python-language-server/.pylintrc +++ /dev/null @@ -1,29 +0,0 @@ -[FORMAT] - -max-line-length = 120 - -[MESSAGES CONTROL] - -enable = - useless-suppression - -disable = - duplicate-code, - invalid-name, - fixme, - missing-docstring, - protected-access, - too-few-public-methods, - too-many-arguments, - too-many-instance-attributes, - import-error - -[REPORTS] - -reports = no - -[TYPECHECK] - -generated-members = - pyls_* - cache_clear diff --git a/external-deps/python-language-server/LICENSE b/external-deps/python-language-server/LICENSE deleted file mode 100644 index 56c842e2625..00000000000 --- a/external-deps/python-language-server/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright 2017 Palantir Technologies, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/external-deps/python-language-server/MANIFEST.in b/external-deps/python-language-server/MANIFEST.in deleted file mode 100644 index 20438d9a329..00000000000 --- a/external-deps/python-language-server/MANIFEST.in +++ /dev/null @@ -1,6 +0,0 @@ -include README.rst -include versioneer.py -include pyls/_version.py -include LICENSE -include .pylintrc -recursive-include test *.py diff --git a/external-deps/python-language-server/README.rst b/external-deps/python-language-server/README.rst deleted file mode 100644 index 0648a8ff2cd..00000000000 --- a/external-deps/python-language-server/README.rst +++ /dev/null @@ -1,161 +0,0 @@ -Python Language Server -====================== - -.. image:: https://circleci.com/gh/palantir/python-language-server.svg?style=shield - :target: https://circleci.com/gh/palantir/python-language-server - -.. image:: https://ci.appveyor.com/api/projects/status/mdacv6fnif7wonl0?svg=true - :target: https://ci.appveyor.com/project/gatesn/python-language-server - -.. image:: https://img.shields.io/github/license/palantir/python-language-server.svg - :target: https://github.com/palantir/python-language-server/blob/master/LICENSE - -A Python 2.7 and 3.5+ implementation of the `Language Server Protocol`_. - -Installation ------------- - -The base language server requires Jedi_ to provide Completions, Definitions, Hover, References, Signature Help, and -Symbols: - -``pip install python-language-server`` - -If the respective dependencies are found, the following optional providers will be enabled: - -* Rope_ for Completions and renaming -* Pyflakes_ linter to detect various errors -* McCabe_ linter for complexity checking -* pycodestyle_ linter for style checking -* pydocstyle_ linter for docstring style checking (disabled by default) -* autopep8_ for code formatting -* YAPF_ for code formatting (preferred over autopep8) - -Optional providers can be installed using the `extras` syntax. To install YAPF_ formatting for example: - -``pip install 'python-language-server[yapf]'`` - -All optional providers can be installed using: - -``pip install 'python-language-server[all]'`` - -If you get an error similar to ``'install_requires' must be a string or list of strings`` then please upgrade setuptools before trying again. - -``pip install -U setuptools`` - -3rd Party Plugins -~~~~~~~~~~~~~~~~~ -Installing these plugins will add extra functionality to the language server: - -* pyls-mypy_ Mypy type checking for Python 3 -* pyls-isort_ Isort import sort code formatting -* pyls-black_ for code formatting using Black_ - -Please see the above repositories for examples on how to write plugins for the Python Language Server. Please file an -issue if you require assistance writing a plugin. - -Configuration -------------- - -Configuration is loaded from zero or more configuration sources. Currently implemented are: - -* pycodestyle: discovered in ~/.config/pycodestyle, setup.cfg, tox.ini and pycodestyle.cfg. -* flake8: discovered in ~/.config/flake8, setup.cfg, tox.ini and flake8.cfg - -The default configuration source is pycodestyle. Change the `pyls.configurationSources` setting to `['flake8']` in -order to respect flake8 configuration instead. - -Overall configuration is computed first from user configuration (in home directory), overridden by configuration -passed in by the language client, and then overriden by configuration discovered in the workspace. - -To enable pydocstyle for linting docstrings add the following setting in your LSP configuration: -``` -"pyls.plugins.pydocstyle.enabled": true -``` - -Language Server Features ------------------------- - -Auto Completion: - -.. image:: https://raw.githubusercontent.com/palantir/python-language-server/develop/resources/auto-complete.gif - -Code Linting with pycodestyle and pyflakes: - -.. image:: https://raw.githubusercontent.com/palantir/python-language-server/develop/resources/linting.gif - -Signature Help: - -.. image:: https://raw.githubusercontent.com/palantir/python-language-server/develop/resources/signature-help.gif - -Go to definition: - -.. image:: https://raw.githubusercontent.com/palantir/python-language-server/develop/resources/goto-definition.gif - -Hover: - -.. image:: https://raw.githubusercontent.com/palantir/python-language-server/develop/resources/hover.gif - -Find References: - -.. image:: https://raw.githubusercontent.com/palantir/python-language-server/develop/resources/references.gif - -Document Symbols: - -.. image:: https://raw.githubusercontent.com/palantir/python-language-server/develop/resources/document-symbols.gif - -Document Formatting: - -.. image:: https://raw.githubusercontent.com/palantir/python-language-server/develop/resources/document-format.gif - -Development ------------ - -To run the test suite: - -``pip install .[test] && pytest`` - -Develop against VS Code -======================= - -The Python language server can be developed against a local instance of Visual Studio Code. - -Install `VSCode `_ - -.. code-block:: bash - - # Setup a virtual env - virtualenv env - . env/bin/activate - - # Install pyls - pip install . - - # Install the vscode-client extension - cd vscode-client - yarn install - - # Run VSCode which is configured to use pyls - # See the bottom of vscode-client/src/extension.ts for info - yarn run vscode -- $PWD/../ - -Then to debug, click View -> Output and in the dropdown will be pyls. -To refresh VSCode, press `Cmd + r` - -License -------- - -This project is made available under the MIT License. - -.. _Language Server Protocol: https://github.com/Microsoft/language-server-protocol -.. _Jedi: https://github.com/davidhalter/jedi -.. _Rope: https://github.com/python-rope/rope -.. _Pyflakes: https://github.com/PyCQA/pyflakes -.. _McCabe: https://github.com/PyCQA/mccabe -.. _pycodestyle: https://github.com/PyCQA/pycodestyle -.. _pydocstyle: https://github.com/PyCQA/pydocstyle -.. _YAPF: https://github.com/google/yapf -.. _autopep8: https://github.com/hhatto/autopep8 -.. _pyls-mypy: https://github.com/tomv564/pyls-mypy -.. _pyls-isort: https://github.com/paradoxxxzero/pyls-isort -.. _pyls-black: https://github.com/rupert/pyls-black -.. _Black: https://github.com/ambv/black diff --git a/external-deps/python-language-server/RELEASE.md b/external-deps/python-language-server/RELEASE.md deleted file mode 100644 index 2311c1b084c..00000000000 --- a/external-deps/python-language-server/RELEASE.md +++ /dev/null @@ -1,11 +0,0 @@ -To release a new version of the PyLS you need to follow these steps: - -* Close the current milestone on Github - -* git pull or git fetch/merge - -* git tag -a X.X.X -m 'Release X.X.X' - -* git push upstream --tags - -* Publish release in our Github Releases page diff --git a/external-deps/python-language-server/appveyor.yml b/external-deps/python-language-server/appveyor.yml deleted file mode 100644 index 69e3e858696..00000000000 --- a/external-deps/python-language-server/appveyor.yml +++ /dev/null @@ -1,32 +0,0 @@ -environment: - global: - APPVEYOR_RDP_PASSWORD: "dcca4c4863E30d56c2e0dda6327370b3#" - matrix: - - PYTHON: "C:\\Python27" - PYTHON_VERSION: "2.7.15" - PYTHON_ARCH: "64" - - - PYTHON: "C:\\Python35" - PYTHON_VERSION: "3.5.7" - PYTHON_ARCH: "64" - -matrix: - fast_finish: true - -init: - - "ECHO %PYTHON% %PYTHON_VERSION% %PYTHON_ARCH%" - -install: - - "%PYTHON%/python.exe -m pip install --upgrade pip setuptools" - - "%PYTHON%/python.exe -m pip install .[all] .[test]" - -test_script: - - "%PYTHON%/Scripts/pytest.exe -v test/" - -# on_finish: -# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) - -build: false # Not a C# project - -cache: - - '%APPDATA%\pip\Cache' diff --git a/external-deps/python-language-server/pyls/__init__.py b/external-deps/python-language-server/pyls/__init__.py deleted file mode 100644 index d3e7ead0fc1..00000000000 --- a/external-deps/python-language-server/pyls/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import os -import sys -import pluggy -from ._version import get_versions - -if sys.version_info[0] < 3: - from future.standard_library import install_aliases - install_aliases() - -__version__ = get_versions()['version'] -del get_versions - -PYLS = 'pyls' - -hookspec = pluggy.HookspecMarker(PYLS) -hookimpl = pluggy.HookimplMarker(PYLS) - -IS_WIN = os.name == 'nt' diff --git a/external-deps/python-language-server/pyls/__main__.py b/external-deps/python-language-server/pyls/__main__.py deleted file mode 100644 index 6440085f05f..00000000000 --- a/external-deps/python-language-server/pyls/__main__.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import argparse -import logging -import logging.config -import sys - -try: - import ujson as json -except Exception: # pylint: disable=broad-except - import json - -from .python_ls import (PythonLanguageServer, start_io_lang_server, - start_tcp_lang_server) - -LOG_FORMAT = "%(asctime)s UTC - %(levelname)s - %(name)s - %(message)s" - - -def add_arguments(parser): - parser.description = "Python Language Server" - - parser.add_argument( - "--tcp", action="store_true", - help="Use TCP server instead of stdio" - ) - parser.add_argument( - "--host", default="127.0.0.1", - help="Bind to this address" - ) - parser.add_argument( - "--port", type=int, default=2087, - help="Bind to this port" - ) - parser.add_argument( - '--check-parent-process', action="store_true", - help="Check whether parent process is still alive using os.kill(ppid, 0) " - "and auto shut down language server process when parent process is not alive." - "Note that this may not work on a Windows machine." - ) - - log_group = parser.add_mutually_exclusive_group() - log_group.add_argument( - "--log-config", - help="Path to a JSON file containing Python logging config." - ) - log_group.add_argument( - "--log-file", - help="Redirect logs to the given file instead of writing to stderr." - "Has no effect if used with --log-config." - ) - - parser.add_argument( - '-v', '--verbose', action='count', default=0, - help="Increase verbosity of log output, overrides log config file" - ) - - -def main(): - parser = argparse.ArgumentParser() - add_arguments(parser) - args = parser.parse_args() - _configure_logger(args.verbose, args.log_config, args.log_file) - - if args.tcp: - start_tcp_lang_server(args.host, args.port, args.check_parent_process, - PythonLanguageServer) - else: - stdin, stdout = _binary_stdio() - start_io_lang_server(stdin, stdout, args.check_parent_process, - PythonLanguageServer) - - -def _binary_stdio(): - """Construct binary stdio streams (not text mode). - - This seems to be different for Window/Unix Python2/3, so going by: - https://stackoverflow.com/questions/2850893/reading-binary-data-from-stdin - """ - PY3K = sys.version_info >= (3, 0) - - if PY3K: - # pylint: disable=no-member - stdin, stdout = sys.stdin.buffer, sys.stdout.buffer - else: - # Python 2 on Windows opens sys.stdin in text mode, and - # binary data that read from it becomes corrupted on \r\n - if sys.platform == "win32": - # set sys.stdin to binary mode - # pylint: disable=no-member,import-error - import os - import msvcrt - msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) - msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) - stdin, stdout = sys.stdin, sys.stdout - - return stdin, stdout - - -def _configure_logger(verbose=0, log_config=None, log_file=None): - root_logger = logging.root - - if log_config: - with open(log_config, 'r') as f: - logging.config.dictConfig(json.load(f)) - else: - formatter = logging.Formatter(LOG_FORMAT) - if log_file: - log_handler = logging.handlers.RotatingFileHandler( - log_file, mode='a', maxBytes=50*1024*1024, - backupCount=10, encoding=None, delay=0 - ) - else: - log_handler = logging.StreamHandler() - log_handler.setFormatter(formatter) - root_logger.addHandler(log_handler) - - if verbose == 0: - level = logging.WARNING - elif verbose == 1: - level = logging.INFO - elif verbose >= 2: - level = logging.DEBUG - - root_logger.setLevel(level) - - -if __name__ == '__main__': - main() diff --git a/external-deps/python-language-server/pyls/_utils.py b/external-deps/python-language-server/pyls/_utils.py deleted file mode 100644 index 919bf1c5064..00000000000 --- a/external-deps/python-language-server/pyls/_utils.py +++ /dev/null @@ -1,200 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -from distutils.version import LooseVersion -import functools -import inspect -import logging -import os -import sys -import threading - -import jedi - -PY2 = sys.version_info.major == 2 -JEDI_VERSION = jedi.__version__ - -if PY2: - import pathlib2 as pathlib -else: - import pathlib - -log = logging.getLogger(__name__) - - -def debounce(interval_s, keyed_by=None): - """Debounce calls to this function until interval_s seconds have passed.""" - def wrapper(func): - timers = {} - lock = threading.Lock() - - @functools.wraps(func) - def debounced(*args, **kwargs): - call_args = inspect.getcallargs(func, *args, **kwargs) - key = call_args[keyed_by] if keyed_by else None - - def run(): - with lock: - del timers[key] - return func(*args, **kwargs) - - with lock: - old_timer = timers.get(key) - if old_timer: - old_timer.cancel() - - timer = threading.Timer(interval_s, run) - timers[key] = timer - timer.start() - return debounced - return wrapper - - -def find_parents(root, path, names): - """Find files matching the given names relative to the given path. - - Args: - path (str): The file path to start searching up from. - names (List[str]): The file/directory names to look for. - root (str): The directory at which to stop recursing upwards. - - Note: - The path MUST be within the root. - """ - if not root: - return [] - - if not os.path.commonprefix((root, path)): - log.warning("Path %s not in %s", path, root) - return [] - - # Split the relative by directory, generate all the parent directories, then check each of them. - # This avoids running a loop that has different base-cases for unix/windows - # e.g. /a/b and /a/b/c/d/e.py -> ['/a/b', 'c', 'd'] - dirs = [root] + os.path.relpath(os.path.dirname(path), root).split(os.path.sep) - - # Search each of /a/b/c, /a/b, /a - while dirs: - search_dir = os.path.join(*dirs) - existing = list(filter(os.path.exists, [os.path.join(search_dir, n) for n in names])) - if existing: - return existing - dirs.pop() - - # Otherwise nothing - return [] - - -def match_uri_to_workspace(uri, workspaces): - if uri is None: - return None - max_len, chosen_workspace = -1, None - path = pathlib.Path(uri).parts - for workspace in workspaces: - try: - workspace_parts = pathlib.Path(workspace).parts - except TypeError: - # This can happen in Python2 if 'value' is a subclass of string - workspace_parts = pathlib.Path(unicode(workspace)).parts - if len(workspace_parts) > len(path): - continue - match_len = 0 - for workspace_part, path_part in zip(workspace_parts, path): - if workspace_part == path_part: - match_len += 1 - if match_len > 0: - if match_len > max_len: - max_len = match_len - chosen_workspace = workspace - return chosen_workspace - - -def list_to_string(value): - return ",".join(value) if isinstance(value, list) else value - - -def merge_dicts(dict_a, dict_b): - """Recursively merge dictionary b into dictionary a. - - If override_nones is True, then - """ - def _merge_dicts_(a, b): - for key in set(a.keys()).union(b.keys()): - if key in a and key in b: - if isinstance(a[key], dict) and isinstance(b[key], dict): - yield (key, dict(_merge_dicts_(a[key], b[key]))) - elif b[key] is not None: - yield (key, b[key]) - else: - yield (key, a[key]) - elif key in a: - yield (key, a[key]) - elif b[key] is not None: - yield (key, b[key]) - 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. - """ - 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 - - -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 - max_column = len(lines[line_number].rstrip('\r\n')) if len(lines) > line_number else 0 - return min(column, max_column) - - -if os.name == 'nt': - import ctypes - - kernel32 = ctypes.windll.kernel32 - PROCESS_QUERY_INFROMATION = 0x1000 - - def is_process_alive(pid): - """Check whether the process with the given pid is still alive. - - Running `os.kill()` on Windows always exits the process, so it can't be used to check for an alive process. - see: https://docs.python.org/3/library/os.html?highlight=os%20kill#os.kill - - Hence ctypes is used to check for the process directly via windows API avoiding any other 3rd-party dependency. - - Args: - pid (int): process ID - - Returns: - bool: False if the process is not alive or don't have permission to check, True otherwise. - """ - process = kernel32.OpenProcess(PROCESS_QUERY_INFROMATION, 0, pid) - if process != 0: - kernel32.CloseHandle(process) - return True - return False - -else: - import errno - - def is_process_alive(pid): - """Check whether the process with the given pid is still alive. - - Args: - pid (int): process ID - - Returns: - bool: False if the process is not alive or don't have permission to check, True otherwise. - """ - if pid < 0: - return False - try: - os.kill(pid, 0) - except OSError as e: - return e.errno == errno.EPERM - else: - return True diff --git a/external-deps/python-language-server/pyls/_version.py b/external-deps/python-language-server/pyls/_version.py deleted file mode 100644 index aab9f7954eb..00000000000 --- a/external-deps/python-language-server/pyls/_version.py +++ /dev/null @@ -1,520 +0,0 @@ -# pylint: skip-file -# This file helps to compute a version number in source trees obtained from -# git-archive tarball (such as those provided by githubs download-from-tag -# feature). Distribution tarballs (built by setup.py sdist) and build -# directories (produced by setup.py build) will contain a much shorter file -# that just contains the computed version number. - -# This file is released into the public domain. Generated by -# versioneer-0.18 (https://github.com/warner/python-versioneer) - -"""Git implementation of _version.py.""" - -import errno -import os -import re -import subprocess -import sys - - -def get_keywords(): - """Get the keywords needed to look up the version information.""" - # these strings will be replaced by git during git-archive. - # setup.py/versioneer.py will grep for the variable names, so they must - # each be defined on a line of their own. _version.py will just call - # get_keywords(). - git_refnames = "$Format:%d$" - git_full = "$Format:%H$" - git_date = "$Format:%ci$" - keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} - return keywords - - -class VersioneerConfig: - """Container for Versioneer configuration parameters.""" - - -def get_config(): - """Create, populate and return the VersioneerConfig() object.""" - # these strings are filled in when 'setup.py versioneer' creates - # _version.py - cfg = VersioneerConfig() - cfg.VCS = "git" - cfg.style = "pep440" - cfg.tag_prefix = "" - cfg.parentdir_prefix = "" - cfg.versionfile_source = "pyls/_version.py" - cfg.verbose = False - return cfg - - -class NotThisMethod(Exception): - """Exception raised if a method is not valid for the current scenario.""" - - -LONG_VERSION_PY = {} -HANDLERS = {} - - -def register_vcs_handler(vcs, method): # decorator - """Decorator to mark a method as the handler for a particular VCS.""" - def decorate(f): - """Store f in HANDLERS[vcs][method].""" - if vcs not in HANDLERS: - HANDLERS[vcs] = {} - HANDLERS[vcs][method] = f - return f - return decorate - - -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): - """Call the given command(s).""" - assert isinstance(commands, list) - p = None - for c in commands: - try: - dispcmd = str([c] + args) - # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) - break - except EnvironmentError: - e = sys.exc_info()[1] - if e.errno == errno.ENOENT: - continue - if verbose: - print("unable to run %s" % dispcmd) - print(e) - return None, None - else: - if verbose: - print("unable to find command, tried %s" % (commands,)) - return None, None - stdout = p.communicate()[0].strip() - if sys.version_info[0] >= 3: - stdout = stdout.decode() - if p.returncode != 0: - if verbose: - print("unable to run %s (error)" % dispcmd) - print("stdout was %s" % stdout) - return None, p.returncode - return stdout, p.returncode - - -def versions_from_parentdir(parentdir_prefix, root, verbose): - """Try to determine the version from the parent directory name. - - Source tarballs conventionally unpack into a directory that includes both - the project name and a version string. We will also support searching up - two directory levels for an appropriately named parent directory - """ - rootdirs = [] - - for i in range(3): - dirname = os.path.basename(root) - if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} - else: - rootdirs.append(root) - root = os.path.dirname(root) # up a level - - if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) - raise NotThisMethod("rootdir doesn't start with parentdir_prefix") - - -@register_vcs_handler("git", "get_keywords") -def git_get_keywords(versionfile_abs): - """Extract version information from the given file.""" - # the code embedded in _version.py can just fetch the value of these - # keywords. When used from setup.py, we don't want to import _version.py, - # so we do it with a regexp instead. This function is not used from - # _version.py. - keywords = {} - try: - f = open(versionfile_abs, "r") - for line in f.readlines(): - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["full"] = mo.group(1) - if line.strip().startswith("git_date ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["date"] = mo.group(1) - f.close() - except EnvironmentError: - pass - return keywords - - -@register_vcs_handler("git", "keywords") -def git_versions_from_keywords(keywords, tag_prefix, verbose): - """Get version information from git keywords.""" - if not keywords: - raise NotThisMethod("no keywords at all, weird") - date = keywords.get("date") - if date is not None: - # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant - # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 - # -like" string, which we must then edit to make compliant), because - # it's been around since git-1.5.3, and it's too difficult to - # discover which version we're using, or to work around using an - # older one. - date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - refnames = keywords["refnames"].strip() - if refnames.startswith("$Format"): - if verbose: - print("keywords are unexpanded, not using") - raise NotThisMethod("unexpanded keywords, not a git-archive tarball") - refs = set([r.strip() for r in refnames.strip("()").split(",")]) - # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of - # just "foo-1.0". If we see a "tag: " prefix, prefer those. - TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) - if verbose: - print("discarding '%s', no digits" % ",".join(refs - tags)) - if verbose: - print("likely tags: %s" % ",".join(sorted(tags))) - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] - if verbose: - print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} - # no suitable tags, so version is "0+unknown", but full hex is still there - if verbose: - print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} - - -@register_vcs_handler("git", "pieces_from_vcs") -def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): - """Get version from 'git describe' in the root of the source tree. - - This only gets called if the git-archive 'subst' keywords were *not* - expanded, and _version.py hasn't already been rewritten with a short - version string, meaning we're inside a checked out source tree. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) - if rc != 0: - if verbose: - print("Directory %s not under git control" % root) - raise NotThisMethod("'git rev-parse --git-dir' returned error") - - # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] - # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%s*" % tag_prefix], - cwd=root) - # --long was added in git-1.5.5 - if describe_out is None: - raise NotThisMethod("'git describe' failed") - describe_out = describe_out.strip() - full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) - if full_out is None: - raise NotThisMethod("'git rev-parse' failed") - full_out = full_out.strip() - - pieces = {} - pieces["long"] = full_out - pieces["short"] = full_out[:7] # maybe improved later - pieces["error"] = None - - # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] - # TAG might have hyphens. - git_describe = describe_out - - # look for -dirty suffix - dirty = git_describe.endswith("-dirty") - pieces["dirty"] = dirty - if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] - - # now we have TAG-NUM-gHEX or HEX - - if "-" in git_describe: - # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) - if not mo: - # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) - return pieces - - # tag - full_tag = mo.group(1) - if not full_tag.startswith(tag_prefix): - if verbose: - fmt = "tag '%s' doesn't start with prefix '%s'" - print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) - return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] - - # distance: number of commits since tag - pieces["distance"] = int(mo.group(2)) - - # commit: short hex revision ID - pieces["short"] = mo.group(3) - - else: - # HEX: no tags - pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) - pieces["distance"] = int(count_out) # total number of commits - - # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], - cwd=root)[0].strip() - pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - - return pieces - - -def plus_or_dot(pieces): - """Return a + if we don't already have one, else return a .""" - if "+" in pieces.get("closest-tag", ""): - return "." - return "+" - - -def render_pep440(pieces): - """Build up version string, with post-release "local version identifier". - - Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you - get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty - - Exceptions: - 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += plus_or_dot(pieces) - rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_pre(pieces): - """TAG[.post.devDISTANCE] -- No -dirty. - - Exceptions: - 1: no tags. 0.post.devDISTANCE - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += ".post.dev%d" % pieces["distance"] - else: - # exception #1 - rendered = "0.post.dev%d" % pieces["distance"] - return rendered - - -def render_pep440_post(pieces): - """TAG[.postDISTANCE[.dev0]+gHEX] . - - The ".dev0" means dirty. Note that .dev0 sorts backwards - (a dirty tree will appear "older" than the corresponding clean one), - but you shouldn't be releasing software with -dirty anyways. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%s" % pieces["short"] - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += "+g%s" % pieces["short"] - return rendered - - -def render_pep440_old(pieces): - """TAG[.postDISTANCE[.dev0]] . - - The ".dev0" means dirty. - - Eexceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - return rendered - - -def render_git_describe(pieces): - """TAG[-DISTANCE-gHEX][-dirty]. - - Like 'git describe --tags --dirty --always'. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render_git_describe_long(pieces): - """TAG-DISTANCE-gHEX[-dirty]. - - Like 'git describe --tags --dirty --always -long'. - The distance/hash is unconditional. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render(pieces, style): - """Render the given version pieces into the requested style.""" - if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} - - if not style or style == "default": - style = "pep440" # the default - - if style == "pep440": - rendered = render_pep440(pieces) - elif style == "pep440-pre": - rendered = render_pep440_pre(pieces) - elif style == "pep440-post": - rendered = render_pep440_post(pieces) - elif style == "pep440-old": - rendered = render_pep440_old(pieces) - elif style == "git-describe": - rendered = render_git_describe(pieces) - elif style == "git-describe-long": - rendered = render_git_describe_long(pieces) - else: - raise ValueError("unknown style '%s'" % style) - - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} - - -def get_versions(): - """Get version information or return default if unable to do so.""" - # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have - # __file__, we can work backwards from there to the root. Some - # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which - # case we can only use expanded keywords. - - cfg = get_config() - verbose = cfg.verbose - - try: - return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, - verbose) - except NotThisMethod: - pass - - try: - root = os.path.realpath(__file__) - # versionfile_source is the relative path from the top of the source - # tree (where the .git directory might live) to this file. Invert - # this to find the root from __file__. - for i in cfg.versionfile_source.split('/'): - root = os.path.dirname(root) - except NameError: - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None} - - try: - pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) - return render(pieces, cfg.style) - except NotThisMethod: - pass - - try: - if cfg.parentdir_prefix: - return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) - except NotThisMethod: - pass - - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", "date": None} diff --git a/external-deps/python-language-server/pyls/config/__init__.py b/external-deps/python-language-server/pyls/config/__init__.py deleted file mode 100644 index 9c6eb52c2ac..00000000000 --- a/external-deps/python-language-server/pyls/config/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. diff --git a/external-deps/python-language-server/pyls/config/config.py b/external-deps/python-language-server/pyls/config/config.py deleted file mode 100644 index 65696d8179b..00000000000 --- a/external-deps/python-language-server/pyls/config/config.py +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import logging -import pkg_resources -try: - from functools import lru_cache -except ImportError: - from backports.functools_lru_cache import lru_cache - -import pluggy - -from pyls import _utils, hookspecs, uris, PYLS - -log = logging.getLogger(__name__) - -# Sources of config, first source overrides next source -DEFAULT_CONFIG_SOURCES = ['pycodestyle'] - - -class Config(object): - - def __init__(self, root_uri, init_opts, process_id, capabilities): - self._root_path = uris.to_fs_path(root_uri) - self._root_uri = root_uri - self._init_opts = init_opts - self._process_id = process_id - self._capabilities = capabilities - - self._settings = {} - self._plugin_settings = {} - - self._config_sources = {} - try: - from .flake8_conf import Flake8Config - self._config_sources['flake8'] = Flake8Config(self._root_path) - except ImportError: - pass - try: - from .pycodestyle_conf import PyCodeStyleConfig - self._config_sources['pycodestyle'] = PyCodeStyleConfig(self._root_path) - except ImportError: - pass - - self._pm = pluggy.PluginManager(PYLS) - self._pm.trace.root.setwriter(log.debug) - self._pm.enable_tracing() - self._pm.add_hookspecs(hookspecs) - - # Pluggy will skip loading a plugin if it throws a DistributionNotFound exception. - # However I don't want all plugins to have to catch ImportError and re-throw. So here we'll filter - # out any entry points that throw ImportError assuming one or more of their dependencies isn't present. - for entry_point in pkg_resources.iter_entry_points(PYLS): - try: - entry_point.load() - except ImportError as e: - log.warning("Failed to load %s entry point '%s': %s", PYLS, entry_point.name, e) - self._pm.set_blocked(entry_point.name) - - # Load the entry points into pluggy, having blocked any failing ones - self._pm.load_setuptools_entrypoints(PYLS) - - for name, plugin in self._pm.list_name_plugin(): - if plugin is not None: - log.info("Loaded pyls plugin %s from %s", name, plugin) - - for plugin_conf in self._pm.hook.pyls_settings(config=self): - self._plugin_settings = _utils.merge_dicts(self._plugin_settings, plugin_conf) - - self._update_disabled_plugins() - - @property - def disabled_plugins(self): - return self._disabled_plugins - - @property - def plugin_manager(self): - return self._pm - - @property - def init_opts(self): - return self._init_opts - - @property - def root_uri(self): - return self._root_uri - - @property - def process_id(self): - return self._process_id - - @property - def capabilities(self): - return self._capabilities - - @lru_cache(maxsize=32) - def settings(self, document_path=None): - """Settings are constructed from a few sources: - - 1. User settings, found in user's home directory - 2. Plugin settings, reported by PyLS plugins - 3. LSP settings, given to us from didChangeConfiguration - 4. Project settings, found in config files in the current project. - - Since this function is nondeterministic, it is important to call - settings.cache_clear() when the config is updated - """ - settings = {} - sources = self._settings.get('configurationSources', DEFAULT_CONFIG_SOURCES) - - for source_name in reversed(sources): - source = self._config_sources.get(source_name) - if not source: - continue - source_conf = source.user_config() - log.debug("Got user config from %s: %s", source.__class__.__name__, source_conf) - settings = _utils.merge_dicts(settings, source_conf) - log.debug("With user configuration: %s", settings) - - settings = _utils.merge_dicts(settings, self._plugin_settings) - log.debug("With plugin configuration: %s", settings) - - settings = _utils.merge_dicts(settings, self._settings) - log.debug("With lsp configuration: %s", settings) - - for source_name in reversed(sources): - source = self._config_sources.get(source_name) - if not source: - continue - source_conf = source.project_config(document_path or self._root_path) - log.debug("Got project config from %s: %s", source.__class__.__name__, source_conf) - settings = _utils.merge_dicts(settings, source_conf) - log.debug("With project configuration: %s", settings) - - return settings - - def find_parents(self, path, names): - root_path = uris.to_fs_path(self._root_uri) - return _utils.find_parents(root_path, path, names) - - def plugin_settings(self, plugin, document_path=None): - return self.settings(document_path=document_path).get('plugins', {}).get(plugin, {}) - - def update(self, settings): - """Recursively merge the given settings into the current settings.""" - self.settings.cache_clear() - self._settings = settings - log.info("Updated settings to %s", self._settings) - self._update_disabled_plugins() - - def _update_disabled_plugins(self): - # All plugins default to enabled - self._disabled_plugins = [ - plugin for name, plugin in self.plugin_manager.list_name_plugin() - if not self.settings().get('plugins', {}).get(name, {}).get('enabled', True) - ] - log.info("Disabled plugins: %s", self._disabled_plugins) diff --git a/external-deps/python-language-server/pyls/config/flake8_conf.py b/external-deps/python-language-server/pyls/config/flake8_conf.py deleted file mode 100644 index 47b6cfad734..00000000000 --- a/external-deps/python-language-server/pyls/config/flake8_conf.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import logging -import os -from pyls._utils import find_parents -from .source import ConfigSource - -log = logging.getLogger(__name__) - -CONFIG_KEY = 'flake8' -PROJECT_CONFIGS = ['.flake8', 'setup.cfg', 'tox.ini'] - -OPTIONS = [ - # mccabe - ('max-complexity', 'plugins.mccabe.threshold', int), - # pycodestyle - ('exclude', 'plugins.pycodestyle.exclude', list), - ('filename', 'plugins.pycodestyle.filename', list), - ('hang-closing', 'plugins.pycodestyle.hangClosing', bool), - ('ignore', 'plugins.pycodestyle.ignore', list), - ('max-line-length', 'plugins.pycodestyle.maxLineLength', int), - ('select', 'plugins.pycodestyle.select', list), - # flake8 - ('exclude', 'plugins.flake8.exclude', list), - ('filename', 'plugins.flake8.filename', list), - ('hang-closing', 'plugins.flake8.hangClosing', bool), - ('ignore', 'plugins.flake8.ignore', list), - ('max-line-length', 'plugins.flake8.maxLineLength', int), - ('select', 'plugins.flake8.select', list), -] - - -class Flake8Config(ConfigSource): - """Parse flake8 configurations.""" - - def user_config(self): - config_file = self._user_config_file() - config = self.read_config_from_files([config_file]) - return self.parse_config(config, CONFIG_KEY, OPTIONS) - - def _user_config_file(self): - if self.is_windows: - return os.path.expanduser('~\\.flake8') - return os.path.join(self.xdg_home, 'flake8') - - def project_config(self, document_path): - files = find_parents(self.root_path, document_path, PROJECT_CONFIGS) - config = self.read_config_from_files(files) - return self.parse_config(config, CONFIG_KEY, OPTIONS) diff --git a/external-deps/python-language-server/pyls/config/pycodestyle_conf.py b/external-deps/python-language-server/pyls/config/pycodestyle_conf.py deleted file mode 100644 index c09375b040c..00000000000 --- a/external-deps/python-language-server/pyls/config/pycodestyle_conf.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import pycodestyle -from pyls._utils import find_parents -from .source import ConfigSource - - -CONFIG_KEY = 'pycodestyle' -USER_CONFIGS = [pycodestyle.USER_CONFIG] if pycodestyle.USER_CONFIG else [] -PROJECT_CONFIGS = ['pycodestyle.cfg', 'setup.cfg', 'tox.ini'] - -OPTIONS = [ - ('exclude', 'plugins.pycodestyle.exclude', list), - ('filename', 'plugins.pycodestyle.filename', list), - ('hang-closing', 'plugins.pycodestyle.hangClosing', bool), - ('ignore', 'plugins.pycodestyle.ignore', list), - ('max-line-length', 'plugins.pycodestyle.maxLineLength', int), - ('select', 'plugins.pycodestyle.select', list), -] - - -class PyCodeStyleConfig(ConfigSource): - - def user_config(self): - config = self.read_config_from_files(USER_CONFIGS) - return self.parse_config(config, CONFIG_KEY, OPTIONS) - - def project_config(self, document_path): - files = find_parents(self.root_path, document_path, PROJECT_CONFIGS) - config = self.read_config_from_files(files) - return self.parse_config(config, CONFIG_KEY, OPTIONS) diff --git a/external-deps/python-language-server/pyls/config/source.py b/external-deps/python-language-server/pyls/config/source.py deleted file mode 100644 index c3442e01044..00000000000 --- a/external-deps/python-language-server/pyls/config/source.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import configparser -import logging -import os -import sys - -log = logging.getLogger(__name__) - - -class ConfigSource(object): - """Base class for implementing a config source.""" - - def __init__(self, root_path): - self.root_path = root_path - self.is_windows = sys.platform == 'win32' - self.xdg_home = os.environ.get( - 'XDG_CONFIG_HOME', os.path.expanduser('~/.config') - ) - - def user_config(self): - """Return user-level (i.e. home directory) configuration.""" - raise NotImplementedError() - - def project_config(self, document_path): - """Return project-level (i.e. workspace directory) configuration.""" - raise NotImplementedError() - - @staticmethod - def read_config_from_files(files): - config = configparser.RawConfigParser() - for filename in files: - if os.path.exists(filename) and not os.path.isdir(filename): - config.read(filename) - - return config - - @staticmethod - def parse_config(config, key, options): - """Parse the config with the given options.""" - conf = {} - for source, destination, opt_type in options: - opt_value = _get_opt(config, key, source, opt_type) - if opt_value is not None: - _set_opt(conf, destination, opt_value) - return conf - - -def _get_opt(config, key, option, opt_type): - """Get an option from a configparser with the given type.""" - for opt_key in [option, option.replace('-', '_')]: - if not config.has_option(key, opt_key): - continue - - if opt_type == bool: - return config.getboolean(key, opt_key) - - if opt_type == int: - return config.getint(key, opt_key) - - if opt_type == str: - return config.get(key, opt_key) - - if opt_type == list: - return _parse_list_opt(config.get(key, opt_key)) - - raise ValueError("Unknown option type: %s" % opt_type) - - -def _parse_list_opt(string): - return [s.strip() for s in string.split(",") if s.strip()] - - -def _set_opt(config_dict, path, value): - """Set the value in the dictionary at the given path if the value is not None.""" - if value is None: - return - - if '.' not in path: - config_dict[path] = value - return - - key, rest = path.split(".", 1) - if key not in config_dict: - config_dict[key] = {} - - _set_opt(config_dict[key], rest, value) diff --git a/external-deps/python-language-server/pyls/hookspecs.py b/external-deps/python-language-server/pyls/hookspecs.py deleted file mode 100644 index 21f2006e79b..00000000000 --- a/external-deps/python-language-server/pyls/hookspecs.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -# pylint: disable=redefined-builtin, unused-argument -from pyls import hookspec - - -@hookspec -def pyls_code_actions(config, workspace, document, range, context): - pass - - -@hookspec -def pyls_code_lens(config, workspace, document): - pass - - -@hookspec -def pyls_commands(config, workspace): - """The list of command strings supported by the server. - - Returns: - List[str]: The supported commands. - """ - - -@hookspec -def pyls_completions(config, workspace, document, position): - pass - - -@hookspec -def pyls_definitions(config, workspace, document, position): - pass - - -@hookspec -def pyls_dispatchers(config, workspace): - pass - - -@hookspec -def pyls_document_did_open(config, workspace, document): - pass - - -@hookspec -def pyls_document_did_save(config, workspace, document): - pass - - -@hookspec -def pyls_document_highlight(config, workspace, document, position): - pass - - -@hookspec -def pyls_document_symbols(config, workspace, document): - pass - - -@hookspec(firstresult=True) -def pyls_execute_command(config, workspace, command, arguments): - pass - - -@hookspec -def pyls_experimental_capabilities(config, workspace): - pass - - -@hookspec(firstresult=True) -def pyls_folding_range(config, workspace, document): - pass - - -@hookspec(firstresult=True) -def pyls_format_document(config, workspace, document): - pass - - -@hookspec(firstresult=True) -def pyls_format_range(config, workspace, document, range): - pass - - -@hookspec(firstresult=True) -def pyls_hover(config, workspace, document, position): - pass - - -@hookspec -def pyls_initialize(config, workspace): - pass - - -@hookspec -def pyls_initialized(): - pass - - -@hookspec -def pyls_lint(config, workspace, document, is_saved): - pass - - -@hookspec -def pyls_references(config, workspace, document, position, exclude_declaration): - pass - - -@hookspec(firstresult=True) -def pyls_rename(config, workspace, document, position, new_name): - pass - - -@hookspec -def pyls_settings(config): - pass - - -@hookspec(firstresult=True) -def pyls_signature_help(config, workspace, document, position): - pass diff --git a/external-deps/python-language-server/pyls/lsp.py b/external-deps/python-language-server/pyls/lsp.py deleted file mode 100644 index 36a8d84228b..00000000000 --- a/external-deps/python-language-server/pyls/lsp.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -"""Some Language Server Protocol constants - -https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md -""" - - -class CompletionItemKind(object): - Text = 1 - Method = 2 - Function = 3 - Constructor = 4 - Field = 5 - Variable = 6 - Class = 7 - Interface = 8 - Module = 9 - Property = 10 - Unit = 11 - Value = 12 - Enum = 13 - Keyword = 14 - Snippet = 15 - Color = 16 - File = 17 - Reference = 18 - - -class DocumentHighlightKind(object): - Text = 1 - Read = 2 - Write = 3 - - -class DiagnosticSeverity(object): - Error = 1 - Warning = 2 - Information = 3 - Hint = 4 - - -class InsertTextFormat(object): - PlainText = 1 - Snippet = 2 - - -class MessageType(object): - Error = 1 - Warning = 2 - Info = 3 - Log = 4 - - -class SymbolKind(object): - File = 1 - Module = 2 - Namespace = 3 - Package = 4 - Class = 5 - Method = 6 - Property = 7 - Field = 8 - Constructor = 9 - Enum = 10 - Interface = 11 - Function = 12 - Variable = 13 - Constant = 14 - String = 15 - Number = 16 - Boolean = 17 - Array = 18 - - -class TextDocumentSyncKind(object): - NONE = 0 - FULL = 1 - INCREMENTAL = 2 diff --git a/external-deps/python-language-server/pyls/plugins/__init__.py b/external-deps/python-language-server/pyls/plugins/__init__.py deleted file mode 100644 index 9c6eb52c2ac..00000000000 --- a/external-deps/python-language-server/pyls/plugins/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. diff --git a/external-deps/python-language-server/pyls/plugins/autopep8_format.py b/external-deps/python-language-server/pyls/plugins/autopep8_format.py deleted file mode 100644 index 61260068481..00000000000 --- a/external-deps/python-language-server/pyls/plugins/autopep8_format.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2018 Palantir Technologies, Inc. -import logging -from autopep8 import fix_code -from pyls import hookimpl - -log = logging.getLogger(__name__) - - -@hookimpl(tryfirst=True) # Prefer autopep8 over YAPF -def pyls_format_document(config, document): - log.info("Formatting document %s with autopep8", document) - return _format(config, document) - - -@hookimpl(tryfirst=True) # Prefer autopep8 over YAPF -def pyls_format_range(config, document, range): # pylint: disable=redefined-builtin - log.info("Formatting document %s in range %s with autopep8", document, range) - - # First we 'round' the range up/down to full lines only - range['start']['character'] = 0 - range['end']['line'] += 1 - range['end']['character'] = 0 - - # Add 1 for 1-indexing vs LSP's 0-indexing - line_range = (range['start']['line'] + 1, range['end']['line'] + 1) - return _format(config, document, line_range=line_range) - - -def _format(config, document, line_range=None): - options = _autopep8_config(config) - if line_range: - options['line_range'] = list(line_range) - - new_source = fix_code(document.source, options=options) - - if new_source == document.source: - return [] - - # I'm too lazy at the moment to parse diffs into TextEdit items - # So let's just return the entire file... - return [{ - 'range': { - 'start': {'line': 0, 'character': 0}, - # End char 0 of the line after our document - 'end': {'line': len(document.lines), 'character': 0} - }, - 'newText': new_source - }] - - -def _autopep8_config(config): - # We user pycodestyle settings to avoid redefining things - settings = config.plugin_settings('pycodestyle') - options = { - 'exclude': settings.get('exclude'), - 'hang_closing': settings.get('hangClosing'), - 'ignore': settings.get('ignore'), - 'max_line_length': settings.get('maxLineLength'), - 'select': settings.get('select'), - } - - # Filter out null options - return {k: v for k, v in options.items() if v} diff --git a/external-deps/python-language-server/pyls/plugins/definition.py b/external-deps/python-language-server/pyls/plugins/definition.py deleted file mode 100644 index 8ec3b1adb01..00000000000 --- a/external-deps/python-language-server/pyls/plugins/definition.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import logging -from pyls import hookimpl, uris - -log = logging.getLogger(__name__) - - -@hookimpl -def pyls_definitions(config, document, position): - settings = config.plugin_settings('jedi_definition') - definitions = document.jedi_script(position).goto_assignments( - follow_imports=settings.get('follow_imports', True), - follow_builtin_imports=settings.get('follow_builtin_imports', True)) - - return [ - { - 'uri': uris.uri_with(document.uri, path=d.module_path), - 'range': { - 'start': {'line': d.line - 1, 'character': d.column}, - 'end': {'line': d.line - 1, 'character': d.column + len(d.name)}, - } - } - for d in definitions if d.is_definition() and _not_internal_definition(d) - ] - - -def _not_internal_definition(definition): - return ( - definition.line is not None and - definition.column is not None and - definition.module_path is not None and - not definition.in_builtin_module() - ) diff --git a/external-deps/python-language-server/pyls/plugins/flake8_lint.py b/external-deps/python-language-server/pyls/plugins/flake8_lint.py deleted file mode 100644 index 69f3f40a685..00000000000 --- a/external-deps/python-language-server/pyls/plugins/flake8_lint.py +++ /dev/null @@ -1,149 +0,0 @@ -# Copyright 2019 Palantir Technologies, Inc. -"""Linter pluging for flake8""" -import logging -from os import path -import re -from subprocess import Popen, PIPE -from pyls import hookimpl, lsp - -log = logging.getLogger(__name__) - - -@hookimpl -def pyls_settings(): - # Default flake8 to disabled - return {'plugins': {'flake8': {'enabled': False}}} - - -@hookimpl -def pyls_lint(config, document): - settings = config.plugin_settings('flake8') - log.debug("Got flake8 settings: %s", settings) - - opts = { - 'config': settings.get('config'), - 'exclude': settings.get('exclude'), - 'filename': settings.get('filename'), - 'hang-closing': settings.get('hangClosing'), - 'ignore': settings.get('ignore'), - 'max-line-length': settings.get('maxLineLength'), - 'select': settings.get('select'), - } - - # flake takes only absolute path to the config. So we should check and - # convert if necessary - if opts.get('config') and not path.isabs(opts.get('config')): - opts['config'] = path.abspath(path.expanduser(path.expandvars( - opts.get('config') - ))) - log.debug("using flake8 with config: %s", opts['config']) - - # Call the flake8 utility then parse diagnostics from stdout - args = build_args(opts, document.path) - output = run_flake8(args) - return parse_stdout(document, output) - - -def run_flake8(args): - """Run flake8 with the provided arguments, logs errors - from stderr if any. - """ - log.debug("Calling flake8 with args: '%s'", args) - try: - cmd = ['flake8'] - cmd.extend(args) - p = Popen(cmd, stdout=PIPE, stderr=PIPE) - except IOError: - log.debug("Can't execute flake8. Trying with 'python -m flake8'") - cmd = ['python', '-m', 'flake8'] - cmd.extend(args) - p = Popen(cmd, stdout=PIPE, stderr=PIPE) - stderr = p.stderr.read().decode() - if stderr: - log.error("Error while running flake8 '%s'", stderr) - stdout = p.stdout - return stdout.read().decode() - - -def build_args(options, doc_path): - """Build arguments for calling flake8. - - Args: - options: dictionary of argument names and their values. - doc_path: path of the document to lint. - """ - args = [doc_path] - for arg_name, arg_val in options.items(): - if arg_val is None: - continue - arg = None - if isinstance(arg_val, list): - arg = '--{}={}'.format(arg_name, ','.join(arg_val)) - elif isinstance(arg_val, bool): - if arg_val: - arg = '--{}'.format(arg_name) - else: - arg = '--{}={}'.format(arg_name, arg_val) - args.append(arg) - return args - - -def parse_stdout(document, stdout): - """ - Build a diagnostics from flake8's output, it should extract every result and format - it into a dict that looks like this: - { - 'source': 'flake8', - 'code': code, # 'E501' - 'range': { - 'start': { - 'line': start_line, - 'character': start_column, - }, - 'end': { - 'line': end_line, - 'character': end_column, - }, - }, - 'message': msg, - 'severity': lsp.DiagnosticSeverity.*, - } - - Args: - document: The document to be linted. - stdout: output from flake8 - Returns: - A list of dictionaries. - """ - - diagnostics = [] - lines = stdout.splitlines() - for raw_line in lines: - parsed_line = re.match(r'(.*):(\d*):(\d*): (\w*) (.*)', raw_line).groups() - if not parsed_line or len(parsed_line) != 5: - log.debug("Flake8 output parser can't parse line '%s'", raw_line) - continue - _, line, character, code, msg = parsed_line - line = int(line) - 1 - character = int(character) - 1 - diagnostics.append( - { - 'source': 'flake8', - 'code': code, - 'range': { - 'start': { - 'line': line, - 'character': character - }, - 'end': { - 'line': line, - # no way to determine the column - 'character': len(document.lines[line]) - } - }, - 'message': msg, - 'severity': lsp.DiagnosticSeverity.Warning, - } - ) - - return diagnostics diff --git a/external-deps/python-language-server/pyls/plugins/folding.py b/external-deps/python-language-server/pyls/plugins/folding.py deleted file mode 100644 index dd476dcb98d..00000000000 --- a/external-deps/python-language-server/pyls/plugins/folding.py +++ /dev/null @@ -1,203 +0,0 @@ -# pylint: disable=len-as-condition -# Copyright 2019 Palantir Technologies, Inc. - -import re - -import parso -import parso.python.tree as tree_nodes - -from pyls import hookimpl - -SKIP_NODES = (tree_nodes.Module, tree_nodes.IfStmt, tree_nodes.TryStmt) -IDENTATION_REGEX = re.compile(r'(\s+).+') - - -@hookimpl -def pyls_folding_range(document): - program = document.source + '\n' - lines = program.splitlines() - tree = parso.parse(program) - ranges = __compute_folding_ranges(tree, lines) - - results = [] - for (start_line, end_line) in ranges: - start_line -= 1 - end_line -= 1 - # If start/end character is not defined, then it defaults to the - # corresponding line last character - results.append({ - 'startLine': start_line, - 'endLine': end_line, - }) - return results - - -def __merge_folding_ranges(left, right): - for start in list(left.keys()): - right_start = right.pop(start, None) - if right_start is not None: - left[start] = max(right_start, start) - left.update(right) - return left - - -def __empty_identation_stack(identation_stack, level_limits, - current_line, folding_ranges): - while identation_stack != []: - upper_level = identation_stack.pop(0) - level_start = level_limits.pop(upper_level) - folding_ranges.append((level_start, current_line)) - return folding_ranges - - -def __match_identation_stack(identation_stack, level, level_limits, - folding_ranges, current_line): - upper_level = identation_stack.pop(0) - while upper_level >= level: - level_start = level_limits.pop(upper_level) - folding_ranges.append((level_start, current_line)) - upper_level = identation_stack.pop(0) - identation_stack.insert(0, upper_level) - return identation_stack, folding_ranges - - -def __compute_folding_ranges_identation(text): - lines = text.splitlines() - folding_ranges = [] - identation_stack = [] - level_limits = {} - current_level = 0 - current_line = 0 - while lines[current_line] == '': - current_line += 1 - for i, line in enumerate(lines): - if i < current_line: - continue - i += 1 - identation_match = IDENTATION_REGEX.match(line) - if identation_match is not None: - whitespace = identation_match.group(1) - level = len(whitespace) - if level > current_level: - level_limits[current_level] = current_line - identation_stack.insert(0, current_level) - current_level = level - elif level < current_level: - identation_stack, folding_ranges = __match_identation_stack( - identation_stack, level, level_limits, folding_ranges, - current_line) - current_level = level - else: - folding_ranges = __empty_identation_stack( - identation_stack, level_limits, current_line, folding_ranges) - current_level = 0 - if line.strip() != '': - current_line = i - folding_ranges = __empty_identation_stack( - identation_stack, level_limits, current_line, folding_ranges) - return dict(folding_ranges) - - -def __check_if_node_is_valid(node): - valid = True - if isinstance(node, tree_nodes.PythonNode): - kind = node.type - valid = kind not in {'decorated', 'parameters', 'dictorsetmaker', - 'testlist_comp'} - if kind == 'suite': - if isinstance(node.parent, tree_nodes.Function): - valid = False - return valid - - -def __handle_skip(stack, skip): - body = stack[skip] - children = [body] - if hasattr(body, 'children'): - children = body.children - stack = stack[:skip] + children + stack[skip + 1:] - node = body - end_line, _ = body.end_pos - return node, end_line - - -def __handle_flow_nodes(node, end_line, stack): - from_keyword = False - if isinstance(node, tree_nodes.Keyword): - from_keyword = True - if node.value in {'if', 'elif', 'with', 'while'}: - node, end_line = __handle_skip(stack, 2) - elif node.value in {'except'}: - first_node = stack[0] - if isinstance(first_node, tree_nodes.Operator): - node, end_line = __handle_skip(stack, 1) - else: - node, end_line = __handle_skip(stack, 2) - elif node.value in {'for'}: - node, end_line = __handle_skip(stack, 4) - elif node.value in {'else'}: - node, end_line = __handle_skip(stack, 1) - return end_line, from_keyword, node, stack - - -def __compute_start_end_lines(node, stack): - start_line, _ = node.start_pos - end_line, _ = node.end_pos - modified = False - end_line, from_keyword, node, stack = __handle_flow_nodes( - node, end_line, stack) - - last_leaf = node.get_last_leaf() - last_newline = isinstance(last_leaf, tree_nodes.Newline) - last_operator = isinstance(last_leaf, tree_nodes.Operator) - node_is_operator = isinstance(node, tree_nodes.Operator) - last_operator = last_operator or not node_is_operator - - end_line -= 1 - - if isinstance(node.parent, tree_nodes.PythonNode) and not from_keyword: - kind = node.type - if kind in {'suite', 'atom', 'atom_expr', 'arglist'}: - if len(stack) > 0: - next_node = stack[0] - next_line, _ = next_node.start_pos - if next_line > end_line: - end_line += 1 - modified = True - if not last_newline and not modified and not last_operator: - end_line += 1 - return start_line, end_line, stack - - -def __compute_folding_ranges(tree, lines): - folding_ranges = {} - stack = [tree] - - while len(stack) > 0: - node = stack.pop(0) - if isinstance(node, tree_nodes.Newline): - # Skip newline nodes - continue - elif isinstance(node, tree_nodes.PythonErrorNode): - # Fallback to identation-based (best-effort) folding - start_line, _ = node.start_pos - start_line -= 1 - padding = [''] * start_line - text = '\n'.join(padding + lines[start_line:]) + '\n' - identation_ranges = __compute_folding_ranges_identation(text) - folding_ranges = __merge_folding_ranges( - folding_ranges, identation_ranges) - break - elif not isinstance(node, SKIP_NODES): - valid = __check_if_node_is_valid(node) - if valid: - start_line, end_line, stack = __compute_start_end_lines( - node, stack) - if end_line > start_line: - current_end = folding_ranges.get(start_line, -1) - folding_ranges[start_line] = max(current_end, end_line) - if hasattr(node, 'children'): - stack = node.children + stack - - folding_ranges = sorted(folding_ranges.items()) - return folding_ranges diff --git a/external-deps/python-language-server/pyls/plugins/highlight.py b/external-deps/python-language-server/pyls/plugins/highlight.py deleted file mode 100644 index 839ffb265b6..00000000000 --- a/external-deps/python-language-server/pyls/plugins/highlight.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import logging -from pyls import hookimpl, lsp - -log = logging.getLogger(__name__) - - -@hookimpl -def pyls_document_highlight(document, position): - usages = document.jedi_script(position).usages() - - def is_valid(definition): - return definition.line is not None and definition.column is not None - - def local_to_document(definition): - return not definition.module_path or definition.module_path == document.path - - return [{ - 'range': { - 'start': {'line': d.line - 1, 'character': d.column}, - 'end': {'line': d.line - 1, 'character': d.column + len(d.name)} - }, - 'kind': lsp.DocumentHighlightKind.Write if d.is_definition() else lsp.DocumentHighlightKind.Read - } for d in usages if is_valid(d) and local_to_document(d)] diff --git a/external-deps/python-language-server/pyls/plugins/hover.py b/external-deps/python-language-server/pyls/plugins/hover.py deleted file mode 100644 index a98c0ea04a0..00000000000 --- a/external-deps/python-language-server/pyls/plugins/hover.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -from distutils.version import LooseVersion -import logging - -from pyls import hookimpl, _utils - -log = logging.getLogger(__name__) - - -@hookimpl -def pyls_hover(document, position): - definitions = document.jedi_script(position).goto_definitions() - 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 ''} - - return {'contents': ''} diff --git a/external-deps/python-language-server/pyls/plugins/jedi_completion.py b/external-deps/python-language-server/pyls/plugins/jedi_completion.py deleted file mode 100644 index caa543a1ff1..00000000000 --- a/external-deps/python-language-server/pyls/plugins/jedi_completion.py +++ /dev/null @@ -1,187 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import logging -import os.path as osp -import parso -from pyls import hookimpl, lsp, _utils - -log = logging.getLogger(__name__) - -# Map to the VSCode type -_TYPE_MAP = { - 'none': lsp.CompletionItemKind.Value, - 'type': lsp.CompletionItemKind.Class, - 'tuple': lsp.CompletionItemKind.Class, - 'dict': lsp.CompletionItemKind.Class, - 'dictionary': lsp.CompletionItemKind.Class, - 'function': lsp.CompletionItemKind.Function, - 'lambda': lsp.CompletionItemKind.Function, - 'generator': lsp.CompletionItemKind.Function, - 'class': lsp.CompletionItemKind.Class, - 'instance': lsp.CompletionItemKind.Reference, - 'method': lsp.CompletionItemKind.Method, - 'builtin': lsp.CompletionItemKind.Class, - 'builtinfunction': lsp.CompletionItemKind.Function, - 'module': lsp.CompletionItemKind.Module, - 'file': lsp.CompletionItemKind.File, - 'path': lsp.CompletionItemKind.Text, - 'xrange': lsp.CompletionItemKind.Class, - 'slice': lsp.CompletionItemKind.Class, - 'traceback': lsp.CompletionItemKind.Class, - 'frame': lsp.CompletionItemKind.Class, - 'buffer': lsp.CompletionItemKind.Class, - 'dictproxy': lsp.CompletionItemKind.Class, - 'funcdef': lsp.CompletionItemKind.Function, - 'property': lsp.CompletionItemKind.Property, - 'import': lsp.CompletionItemKind.Module, - 'keyword': lsp.CompletionItemKind.Keyword, - 'constant': lsp.CompletionItemKind.Variable, - 'variable': lsp.CompletionItemKind.Variable, - 'value': lsp.CompletionItemKind.Value, - 'param': lsp.CompletionItemKind.Variable, - 'statement': lsp.CompletionItemKind.Keyword, -} - -# Types of parso nodes for which snippet is not included in the completion -_IMPORTS = ('import_name', 'import_from') - -# Types of parso node for errors -_ERRORS = ('error_node', ) - - -@hookimpl -def pyls_completions(config, document, position): - try: - definitions = document.jedi_script(position).completions() - except AttributeError as e: - if 'CompiledObject' in str(e): - # Needed to handle missing CompiledObject attribute - # 'sub_modules_dict' - definitions = None - else: - raise e - - if not definitions: - return None - - completion_capabilities = config.capabilities.get('textDocument', {}).get('completion', {}) - snippet_support = completion_capabilities.get('completionItem', {}).get('snippetSupport') - - 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 - - -def is_exception_class(name): - """ - Determine if a class name is an instance of an Exception. - - This returns `False` if the name given corresponds with a instance of - the 'Exception' class, `True` otherwise - """ - try: - return name in [cls.__name__ for cls in Exception.__subclasses__()] - except AttributeError: - # Needed in case a class don't uses new-style - # class definition in Python 2 - return False - - -def use_snippets(document, position): - """ - Determine if it's necessary to return snippets in code completions. - - This returns `False` if a completion is being requested on an import - statement, `True` otherwise. - """ - line = position['line'] - lines = document.source.split('\n', line) - act_lines = [lines[line][:position['character']]] - line -= 1 - last_character = '' - while line > -1: - act_line = lines[line] - if (act_line.rstrip().endswith('\\') or - act_line.rstrip().endswith('(') or - act_line.rstrip().endswith(',')): - act_lines.insert(0, act_line) - line -= 1 - if act_line.rstrip().endswith('('): - # Needs to be added to the end of the code before parsing - # to make it valid, otherwise the node type could end - # being an 'error_node' for multi-line imports that use '(' - last_character = ')' - else: - break - if '(' in act_lines[-1].strip(): - last_character = ')' - code = '\n'.join(act_lines).split(';')[-1].strip() + last_character - tokens = parso.parse(code) - expr_type = tokens.children[0].type - return (expr_type not in _IMPORTS and - not (expr_type in _ERRORS and 'import' in code)) - - -def _format_completion(d, include_params=True): - completion = { - 'label': _label(d), - 'kind': _TYPE_MAP.get(d.type), - 'detail': _detail(d), - 'documentation': _utils.format_docstring(d.docstring()), - 'sortText': _sort_text(d), - 'insertText': d.name - } - - if d.type == 'path': - path = osp.normpath(d.name) - path = path.replace('\\', '\\\\') - 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 - if '=' not in param.description and - param.name not in {'/', '*'}] - - if len(positional_args) > 1: - # For completions with params, we can generate a snippet instead - completion['insertTextFormat'] = lsp.InsertTextFormat.Snippet - snippet = d.name + '(' - for i, param in enumerate(positional_args): - snippet += '${%s:%s}' % (i + 1, param.name) - if i < len(positional_args) - 1: - snippet += ', ' - snippet += ')$0' - completion['insertText'] = snippet - elif len(positional_args) == 1: - completion['insertText'] = d.name + '($0)' - else: - completion['insertText'] = d.name + '()' - - return completion - - -def _label(definition): - if definition.type in ('function', 'method') and hasattr(definition, 'params'): - params = ', '.join([param.name for param in definition.params]) - return '{}({})'.format(definition.name, params) - - return definition.name - - -def _detail(definition): - try: - return definition.parent().full_name or '' - except AttributeError: - return definition.full_name or '' - - -def _sort_text(definition): - """ Ensure builtins appear at the bottom. - Description is of format : . - """ - - # If its 'hidden', put it next last - prefix = 'z{}' if definition.name.startswith('_') else 'a{}' - return prefix.format(definition.name) diff --git a/external-deps/python-language-server/pyls/plugins/mccabe_lint.py b/external-deps/python-language-server/pyls/plugins/mccabe_lint.py deleted file mode 100644 index 31fb39a9819..00000000000 --- a/external-deps/python-language-server/pyls/plugins/mccabe_lint.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import ast -import logging -import mccabe -from pyls import hookimpl, lsp - -log = logging.getLogger(__name__) - -THRESHOLD = 'threshold' -DEFAULT_THRESHOLD = 15 - - -@hookimpl -def pyls_lint(config, document): - threshold = config.plugin_settings('mccabe').get(THRESHOLD, DEFAULT_THRESHOLD) - log.debug("Running mccabe lint with threshold: %s", threshold) - - try: - tree = compile(document.source, document.path, "exec", ast.PyCF_ONLY_AST) - except SyntaxError: - # We'll let the other linters point this one out - return None - - visitor = mccabe.PathGraphingAstVisitor() - visitor.preorder(tree, visitor) - - diags = [] - for graph in visitor.graphs.values(): - if graph.complexity() >= threshold: - diags.append({ - 'source': 'mccabe', - 'range': { - 'start': {'line': graph.lineno - 1, 'character': graph.column}, - 'end': {'line': graph.lineno - 1, 'character': len(document.lines[graph.lineno])}, - }, - 'message': 'Cyclomatic complexity too high: %s (threshold %s)' % (graph.complexity(), threshold), - 'severity': lsp.DiagnosticSeverity.Warning - }) - - return diags diff --git a/external-deps/python-language-server/pyls/plugins/preload_imports.py b/external-deps/python-language-server/pyls/plugins/preload_imports.py deleted file mode 100644 index b00552cff1a..00000000000 --- a/external-deps/python-language-server/pyls/plugins/preload_imports.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import logging -from pyls import hookimpl - -log = logging.getLogger(__name__) - -MODULES = [ - "OpenGL", "PIL", - "array", "audioop", "binascii", "cPickle", "cStringIO", "cmath", "collections", - "datetime", "errno", "exceptions", "gc", "imageop", "imp", "itertools", - "marshal", "math", "matplotlib", "mmap", "mpmath", "msvcrt", "networkx", "nose", "nt", - "numpy", "operator", "os", "os.path", "pandas", "parser", "rgbimg", "scipy", "signal", - "skimage", "sklearn", "statsmodels", "strop", "sympy", "sys", "thread", "time", - "wx", "xxsubtype", "zipimport", "zlib" -] - - -@hookimpl -def pyls_settings(): - # Setup default modules to preload, and rope extension modules - return { - 'plugins': {'preload': {'modules': MODULES}}, - 'rope': {'extensionModules': MODULES} - } - - -@hookimpl -def pyls_initialize(config): - for mod_name in config.plugin_settings('preload').get('modules', []): - try: - __import__(mod_name) - log.debug("Preloaded module %s", mod_name) - except ImportError: - pass diff --git a/external-deps/python-language-server/pyls/plugins/pycodestyle_lint.py b/external-deps/python-language-server/pyls/plugins/pycodestyle_lint.py deleted file mode 100644 index c12f9f48f11..00000000000 --- a/external-deps/python-language-server/pyls/plugins/pycodestyle_lint.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import logging -import pycodestyle -from autopep8 import continued_indentation as autopep8_c_i -from pyls import hookimpl, lsp - -# Check if autopep8's continued_indentation implementation -# is overriding pycodestyle's and if so, re-register -# the check using pycodestyle's implementation as expected -if autopep8_c_i in pycodestyle._checks['logical_line']: - del pycodestyle._checks['logical_line'][autopep8_c_i] - pycodestyle.register_check(pycodestyle.continued_indentation) - -log = logging.getLogger(__name__) - - -@hookimpl -def pyls_lint(config, document): - settings = config.plugin_settings('pycodestyle') - log.debug("Got pycodestyle settings: %s", settings) - - opts = { - 'exclude': settings.get('exclude'), - 'filename': settings.get('filename'), - 'hang_closing': settings.get('hangClosing'), - 'ignore': settings.get('ignore'), - 'max_line_length': settings.get('maxLineLength'), - 'select': settings.get('select'), - } - kwargs = {k: v for k, v in opts.items() if v} - styleguide = pycodestyle.StyleGuide(kwargs) - - c = pycodestyle.Checker( - filename=document.uri, lines=document.lines, options=styleguide.options, - report=PyCodeStyleDiagnosticReport(styleguide.options) - ) - c.check_all() - diagnostics = c.report.diagnostics - - return diagnostics - - -class PyCodeStyleDiagnosticReport(pycodestyle.BaseReport): - - def __init__(self, options): - self.diagnostics = [] - super(PyCodeStyleDiagnosticReport, self).__init__(options=options) - - def error(self, line_number, offset, text, check): - code = text[:4] - if self._ignore_code(code): - return - - # Don't care about expected errors or warnings - if code in self.expected: - return - - # PyCodeStyle will sometimes give you an error the line after the end of the file - # e.g. no newline at end of file - # In that case, the end offset should just be some number ~100 - # (because why not? There's nothing to underline anyways) - err_range = { - 'start': {'line': line_number - 1, 'character': offset}, - 'end': { - # FIXME: It's a little naiive to mark until the end of the line, can we not easily do better? - 'line': line_number - 1, - 'character': 100 if line_number > len(self.lines) else len(self.lines[line_number - 1]) - }, - } - self.diagnostics.append({ - 'source': 'pycodestyle', - 'range': err_range, - 'message': text, - 'code': code, - # Are style errors really ever errors? - 'severity': lsp.DiagnosticSeverity.Warning - }) diff --git a/external-deps/python-language-server/pyls/plugins/pydocstyle_lint.py b/external-deps/python-language-server/pyls/plugins/pydocstyle_lint.py deleted file mode 100644 index d00bda95489..00000000000 --- a/external-deps/python-language-server/pyls/plugins/pydocstyle_lint.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import contextlib -import logging -import os -import re -import sys - -import pydocstyle -from pyls import hookimpl, lsp - -log = logging.getLogger(__name__) - -# PyDocstyle is a little verbose in debug message -pydocstyle_logger = logging.getLogger(pydocstyle.utils.__name__) -pydocstyle_logger.setLevel(logging.INFO) - -DEFAULT_MATCH_RE = pydocstyle.config.ConfigurationParser.DEFAULT_MATCH_RE -DEFAULT_MATCH_DIR_RE = pydocstyle.config.ConfigurationParser.DEFAULT_MATCH_DIR_RE - - -@hookimpl -def pyls_settings(): - # Default pydocstyle to disabled - return {'plugins': {'pydocstyle': {'enabled': False}}} - - -@hookimpl -def pyls_lint(config, document): - settings = config.plugin_settings('pydocstyle') - log.debug("Got pydocstyle settings: %s", settings) - - # Explicitly passing a path to pydocstyle means it doesn't respect the --match flag, so do it ourselves - filename_match_re = re.compile(settings.get('match', DEFAULT_MATCH_RE) + '$') - if not filename_match_re.match(os.path.basename(document.path)): - return [] - - # Likewise with --match-dir - dir_match_re = re.compile(settings.get('matchDir', DEFAULT_MATCH_DIR_RE) + '$') - if not dir_match_re.match(os.path.basename(os.path.dirname(document.path))): - return [] - - args = [document.path] - - if settings.get('convention'): - args.append('--convention=' + settings['convention']) - - if settings.get('addSelect'): - args.append('--add-select=' + ','.join(settings['addSelect'])) - if settings.get('addIgnore'): - args.append('--add-ignore=' + ','.join(settings['addIgnore'])) - - elif settings.get('select'): - args.append('--select=' + ','.join(settings['select'])) - elif settings.get('ignore'): - args.append('--ignore=' + ','.join(settings['ignore'])) - - log.info("Using pydocstyle args: %s", args) - - conf = pydocstyle.config.ConfigurationParser() - with _patch_sys_argv(args): - # TODO(gatesn): We can add more pydocstyle args here from our pyls config - conf.parse() - - # Will only yield a single filename, the document path - diags = [] - for filename, checked_codes, ignore_decorators in conf.get_files_to_check(): - errors = pydocstyle.checker.ConventionChecker().check_source( - document.source, filename, ignore_decorators=ignore_decorators - ) - - try: - for error in errors: - if error.code not in checked_codes: - continue - diags.append(_parse_diagnostic(document, error)) - except pydocstyle.parser.ParseError: - # In the case we cannot parse the Python file, just continue - pass - - log.debug("Got pydocstyle errors: %s", diags) - return diags - - -def _parse_diagnostic(document, error): - lineno = error.definition.start - 1 - line = document.lines[0] if document.lines else "" - - start_character = len(line) - len(line.lstrip()) - end_character = len(line) - - return { - 'source': 'pydocstyle', - 'code': error.code, - 'message': error.message, - 'severity': lsp.DiagnosticSeverity.Warning, - 'range': { - 'start': { - 'line': lineno, - 'character': start_character - }, - 'end': { - 'line': lineno, - 'character': end_character - } - } - } - - -@contextlib.contextmanager -def _patch_sys_argv(arguments): - old_args = sys.argv - - # Preserve argv[0] since it's the executable - sys.argv = old_args[0:1] + arguments - - try: - yield - finally: - sys.argv = old_args diff --git a/external-deps/python-language-server/pyls/plugins/pyflakes_lint.py b/external-deps/python-language-server/pyls/plugins/pyflakes_lint.py deleted file mode 100644 index c37aad89225..00000000000 --- a/external-deps/python-language-server/pyls/plugins/pyflakes_lint.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -from pyflakes import api as pyflakes_api, messages -from pyls import hookimpl, lsp - -# Pyflakes messages that should be reported as Errors instead of Warns -PYFLAKES_ERROR_MESSAGES = ( - messages.UndefinedName, - messages.UndefinedExport, - messages.UndefinedLocal, - messages.DuplicateArgument, - messages.FutureFeatureNotDefined, - messages.ReturnOutsideFunction, - messages.YieldOutsideFunction, - messages.ContinueOutsideLoop, - messages.BreakOutsideLoop, - messages.ContinueInFinally, - messages.TwoStarredExpressions, -) - - -@hookimpl -def pyls_lint(document): - reporter = PyflakesDiagnosticReport(document.lines) - pyflakes_api.check(document.source.encode('utf-8'), document.path, reporter=reporter) - return reporter.diagnostics - - -class PyflakesDiagnosticReport(object): - - def __init__(self, lines): - self.lines = lines - self.diagnostics = [] - - def unexpectedError(self, _filename, msg): # pragma: no cover - err_range = { - 'start': {'line': 0, 'character': 0}, - 'end': {'line': 0, 'character': 0}, - } - self.diagnostics.append({ - 'source': 'pyflakes', - 'range': err_range, - 'message': msg, - 'severity': lsp.DiagnosticSeverity.Error, - }) - - def syntaxError(self, _filename, msg, lineno, offset, text): - # We've seen that lineno and offset can sometimes be None - lineno = lineno or 1 - offset = offset or 0 - - err_range = { - 'start': {'line': lineno - 1, 'character': offset}, - 'end': {'line': lineno - 1, 'character': offset + len(text)}, - } - self.diagnostics.append({ - 'source': 'pyflakes', - 'range': err_range, - 'message': msg, - 'severity': lsp.DiagnosticSeverity.Error, - }) - - def flake(self, message): - """ Get message like :: """ - err_range = { - 'start': {'line': message.lineno - 1, 'character': message.col}, - 'end': {'line': message.lineno - 1, 'character': len(self.lines[message.lineno - 1])}, - } - - severity = lsp.DiagnosticSeverity.Warning - for message_type in PYFLAKES_ERROR_MESSAGES: - if isinstance(message, message_type): - severity = lsp.DiagnosticSeverity.Error - break - - self.diagnostics.append({ - 'source': 'pyflakes', - 'range': err_range, - 'message': message.message % message.message_args, - 'severity': severity - }) diff --git a/external-deps/python-language-server/pyls/plugins/pylint_lint.py b/external-deps/python-language-server/pyls/plugins/pylint_lint.py deleted file mode 100644 index 9a412637ba2..00000000000 --- a/external-deps/python-language-server/pyls/plugins/pylint_lint.py +++ /dev/null @@ -1,165 +0,0 @@ -# Copyright 2018 Google LLC. -"""Linter plugin for pylint.""" -import collections -import logging -import sys - -from pylint.epylint import py_run -from pyls import hookimpl, lsp - -try: - import ujson as json -except Exception: # pylint: disable=broad-except - import json - -log = logging.getLogger(__name__) - - -class PylintLinter(object): - last_diags = collections.defaultdict(list) - - @classmethod - def lint(cls, document, is_saved, flags=''): - """Plugin interface to pyls linter. - - Args: - document: The document to be linted. - is_saved: Whether or not the file has been saved to disk. - flags: Additional flags to pass to pylint. Not exposed to - pyls_lint, but used for testing. - - Returns: - A list of dicts with the following format: - - { - 'source': 'pylint', - 'range': { - 'start': { - 'line': start_line, - 'character': start_column, - }, - 'end': { - 'line': end_line, - 'character': end_column, - }, - } - 'message': msg, - 'severity': lsp.DiagnosticSeverity.*, - } - """ - if not is_saved: - # Pylint can only be run on files that have been saved to disk. - # Rather than return nothing, return the previous list of - # diagnostics. If we return an empty list, any diagnostics we'd - # previously shown will be cleared until the next save. Instead, - # continue showing (possibly stale) diagnostics until the next - # save. - return cls.last_diags[document.path] - - # py_run will call shlex.split on its arguments, and shlex.split does - # not handle Windows paths (it will try to perform escaping). Turn - # backslashes into forward slashes first to avoid this issue. - path = document.path - if sys.platform.startswith('win'): - path = path.replace('\\', '/') - - pylint_call = '{} -f json {}'.format(path, flags) - log.debug("Calling pylint with '%s'", pylint_call) - json_out, err = py_run(pylint_call, return_std=True) - - # Get strings - json_out = json_out.getvalue() - err = err.getvalue() - - if err != '': - log.error("Error calling pylint: '%s'", err) - - # pylint prints nothing rather than [] when there are no diagnostics. - # json.loads will not parse an empty string, so just return. - if not json_out.strip(): - cls.last_diags[document.path] = [] - return [] - - # Pylint's JSON output is a list of objects with the following format. - # - # { - # "obj": "main", - # "path": "foo.py", - # "message": "Missing function docstring", - # "message-id": "C0111", - # "symbol": "missing-docstring", - # "column": 0, - # "type": "convention", - # "line": 5, - # "module": "foo" - # } - # - # The type can be any of: - # - # * convention - # * error - # * fatal - # * refactor - # * warning - diagnostics = [] - for diag in json.loads(json_out): - # pylint lines index from 1, pyls lines index from 0 - line = diag['line'] - 1 - - err_range = { - 'start': { - 'line': line, - # Index columns start from 0 - 'character': diag['column'], - }, - 'end': { - 'line': line, - # It's possible that we're linting an empty file. Even an empty - # file might fail linting if it isn't named properly. - 'character': len(document.lines[line]) if document.lines else 0, - }, - } - - if diag['type'] == 'convention': - severity = lsp.DiagnosticSeverity.Information - elif diag['type'] == 'error': - severity = lsp.DiagnosticSeverity.Error - elif diag['type'] == 'fatal': - severity = lsp.DiagnosticSeverity.Error - elif diag['type'] == 'refactor': - severity = lsp.DiagnosticSeverity.Hint - elif diag['type'] == 'warning': - severity = lsp.DiagnosticSeverity.Warning - - diagnostics.append({ - 'source': 'pylint', - 'range': err_range, - 'message': '[{}] {}'.format(diag['symbol'], diag['message']), - 'severity': severity, - 'code': diag['message-id'] - }) - cls.last_diags[document.path] = diagnostics - return diagnostics - - -def _build_pylint_flags(settings): - """Build arguments for calling pylint.""" - pylint_args = settings.get('args') - if pylint_args is None: - return '' - return ' '.join(pylint_args) - - -@hookimpl -def pyls_settings(): - # Default pylint to disabled because it requires a config - # file to be useful. - return {'plugins': {'pylint': {'enabled': False, 'args': []}}} - - -@hookimpl -def pyls_lint(config, document, is_saved): - settings = config.plugin_settings('pylint') - log.debug("Got pylint settings: %s", settings) - flags = _build_pylint_flags(settings) - return PylintLinter.lint(document, is_saved, flags=flags) diff --git a/external-deps/python-language-server/pyls/plugins/references.py b/external-deps/python-language-server/pyls/plugins/references.py deleted file mode 100644 index 120cde41b48..00000000000 --- a/external-deps/python-language-server/pyls/plugins/references.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import logging -from pyls import hookimpl, uris - -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() - - if exclude_declaration: - # Filter out if the usage is the actual declaration of the thing - usages = [d for d in usages if not d.is_definition()] - - # Filter out builtin modules - return [{ - 'uri': uris.uri_with(document.uri, path=d.module_path) if d.module_path else document.uri, - 'range': { - 'start': {'line': d.line - 1, 'character': d.column}, - 'end': {'line': d.line - 1, 'character': d.column + len(d.name)} - } - } for d in usages if not d.in_builtin_module()] diff --git a/external-deps/python-language-server/pyls/plugins/rope_completion.py b/external-deps/python-language-server/pyls/plugins/rope_completion.py deleted file mode 100644 index e556e464e8d..00000000000 --- a/external-deps/python-language-server/pyls/plugins/rope_completion.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import logging -from rope.contrib.codeassist import code_assist, sorted_proposals - -from pyls import hookimpl, lsp - - -log = logging.getLogger(__name__) - - -@hookimpl -def pyls_settings(): - # Default rope_completion to disabled - return {'plugins': {'rope_completion': {'enabled': False}}} - - -@hookimpl -def pyls_completions(config, workspace, document, position): - # Rope is a bit rubbish at completing module imports, so we'll return None - word = document.word_at_position({ - # The -1 should really be trying to look at the previous word, but that might be quite expensive - # So we only skip import completions when the cursor is one space after `import` - 'line': position['line'], 'character': max(position['character'] - 1, 0), - }) - if word == 'import': - return None - - offset = document.offset_at_position(position) - rope_config = config.settings(document_path=document.path).get('rope', {}) - rope_project = workspace._rope_project_builder(rope_config) - document_rope = document._rope_resource(rope_config) - - try: - definitions = code_assist(rope_project, document.source, offset, document_rope, maxfixes=3) - except Exception as e: # pylint: disable=broad-except - log.debug("Failed to run Rope code assist: %s", e) - return [] - - definitions = sorted_proposals(definitions) - new_definitions = [] - for d in definitions: - try: - doc = d.get_doc() - except AttributeError: - doc = None - new_definitions.append({ - 'label': d.name, - 'kind': _kind(d), - 'detail': '{0} {1}'.format(d.scope or "", d.name), - 'documentation': doc or "", - 'sortText': _sort_text(d) - }) - definitions = new_definitions - - return definitions or None - - -def _sort_text(definition): - """ Ensure builtins appear at the bottom. - Description is of format : . - """ - if definition.name.startswith("_"): - # It's a 'hidden' func, put it next last - return 'z' + definition.name - elif definition.scope == 'builtin': - return 'y' + definition.name - - # Else put it at the front - return 'a' + definition.name - - -def _kind(d): - """ Return the VSCode type """ - MAP = { - 'none': lsp.CompletionItemKind.Value, - 'type': lsp.CompletionItemKind.Class, - 'tuple': lsp.CompletionItemKind.Class, - 'dict': lsp.CompletionItemKind.Class, - 'dictionary': lsp.CompletionItemKind.Class, - 'function': lsp.CompletionItemKind.Function, - 'lambda': lsp.CompletionItemKind.Function, - 'generator': lsp.CompletionItemKind.Function, - 'class': lsp.CompletionItemKind.Class, - 'instance': lsp.CompletionItemKind.Reference, - 'method': lsp.CompletionItemKind.Method, - 'builtin': lsp.CompletionItemKind.Class, - 'builtinfunction': lsp.CompletionItemKind.Function, - 'module': lsp.CompletionItemKind.Module, - 'file': lsp.CompletionItemKind.File, - 'xrange': lsp.CompletionItemKind.Class, - 'slice': lsp.CompletionItemKind.Class, - 'traceback': lsp.CompletionItemKind.Class, - 'frame': lsp.CompletionItemKind.Class, - 'buffer': lsp.CompletionItemKind.Class, - 'dictproxy': lsp.CompletionItemKind.Class, - 'funcdef': lsp.CompletionItemKind.Function, - 'property': lsp.CompletionItemKind.Property, - 'import': lsp.CompletionItemKind.Module, - 'keyword': lsp.CompletionItemKind.Keyword, - 'constant': lsp.CompletionItemKind.Variable, - 'variable': lsp.CompletionItemKind.Variable, - 'value': lsp.CompletionItemKind.Value, - 'param': lsp.CompletionItemKind.Variable, - 'statement': lsp.CompletionItemKind.Keyword, - } - - return MAP.get(d.type) diff --git a/external-deps/python-language-server/pyls/plugins/rope_rename.py b/external-deps/python-language-server/pyls/plugins/rope_rename.py deleted file mode 100644 index 3dec3153556..00000000000 --- a/external-deps/python-language-server/pyls/plugins/rope_rename.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import logging -import os - -from rope.base import libutils -from rope.refactor.rename import Rename - -from pyls import hookimpl, uris - -log = logging.getLogger(__name__) - - -@hookimpl -def pyls_rename(config, workspace, document, position, new_name): - rope_config = config.settings(document_path=document.path).get('rope', {}) - rope_project = workspace._rope_project_builder(rope_config) - - rename = Rename( - rope_project, - libutils.path_to_resource(rope_project, document.path), - document.offset_at_position(position) - ) - - log.debug("Executing rename of %s to %s", document.word_at_position(position), new_name) - changeset = rename.get_changes(new_name, in_hierarchy=True, docs=True) - log.debug("Finished rename: %s", changeset.changes) - return { - 'documentChanges': [{ - 'textDocument': { - 'uri': uris.uri_with( - document.uri, path=os.path.join(workspace.root_path, change.resource.path) - ), - 'version': workspace.get_document(document.uri).version - }, - 'edits': [{ - 'range': { - 'start': {'line': 0, 'character': 0}, - 'end': {'line': _num_lines(change.resource), 'character': 0}, - }, - 'newText': change.new_contents - }] - } for change in changeset.changes] - } - - -def _num_lines(resource): - "Count the number of lines in a `File` resource." - return len(resource.read().splitlines()) diff --git a/external-deps/python-language-server/pyls/plugins/signature.py b/external-deps/python-language-server/pyls/plugins/signature.py deleted file mode 100644 index 6c509272702..00000000000 --- a/external-deps/python-language-server/pyls/plugins/signature.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import logging -import re -from pyls import hookimpl, _utils - -log = logging.getLogger(__name__) - -SPHINX = re.compile(r"\s*:param\s+(?P\w+):\s*(?P[^\n]+)") -EPYDOC = re.compile(r"\s*@param\s+(?P\w+):\s*(?P[^\n]+)") -GOOGLE = re.compile(r"\s*(?P\w+).*:\s*(?P[^\n]+)") - -DOC_REGEX = [SPHINX, EPYDOC, GOOGLE] - - -@hookimpl -def pyls_signature_help(document, position): - signatures = document.jedi_script(position).call_signatures() - - if not signatures: - return {'signatures': []} - - s = signatures[0] - - # 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 = ' '.join([line.strip() for line in function_sig_lines]) - sig = { - 'label': function_sig, - 'documentation': _utils.format_docstring(s.docstring(raw=True)) - } - - # If there are params, add those - if s.params: - sig['parameters'] = [{ - 'label': p.name, - 'documentation': _param_docs(s.docstring(), p.name) - } for p in s.params] - - # We only return a single signature because Python doesn't allow overloading - sig_info = {'signatures': [sig], 'activeSignature': 0} - - if s.index is not None and s.params: - # Then we know which parameter we're looking at - sig_info['activeParameter'] = s.index - - return sig_info - - -def _param_docs(docstring, param_name): - for line in docstring.splitlines(): - for regex in DOC_REGEX: - m = regex.match(line) - if not m: - continue - if m.group('param') != param_name: - continue - return m.group('doc') or "" diff --git a/external-deps/python-language-server/pyls/plugins/symbols.py b/external-deps/python-language-server/pyls/plugins/symbols.py deleted file mode 100644 index ced9721893b..00000000000 --- a/external-deps/python-language-server/pyls/plugins/symbols.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import logging -from pyls import hookimpl -from pyls.lsp import SymbolKind - -log = logging.getLogger(__name__) - - -@hookimpl -def pyls_document_symbols(config, document): - all_scopes = config.plugin_settings('jedi_symbols').get('all_scopes', True) - definitions = document.jedi_names(all_scopes=all_scopes) - return [{ - 'name': d.name, - 'containerName': _container(d), - 'location': { - 'uri': document.uri, - 'range': _range(d), - }, - 'kind': _kind(d), - } for d in definitions if _include_def(d)] - - -def _include_def(definition): - return ( - # Don't tend to include parameters as symbols - definition.type != 'param' and - # Unused vars should also be skipped - definition.name != '_' and - _kind(definition) is not None - ) - - -def _container(definition): - try: - # Jedi sometimes fails here. - parent = definition.parent() - # Here we check that a grand-parent exists to avoid declaring symbols - # as children of the module. - if parent.parent(): - return parent.name - except: # pylint: disable=bare-except - return None - - return None - - -def _range(definition): - # This gets us more accurate end position - definition = definition._name.tree_name.get_definition() - (start_line, start_column) = definition.start_pos - (end_line, end_column) = definition.end_pos - return { - 'start': {'line': start_line - 1, 'character': start_column}, - 'end': {'line': end_line - 1, 'character': end_column} - } - - -_SYMBOL_KIND_MAP = { - 'none': SymbolKind.Variable, - 'type': SymbolKind.Class, - 'tuple': SymbolKind.Class, - 'dict': SymbolKind.Class, - 'dictionary': SymbolKind.Class, - 'function': SymbolKind.Function, - 'lambda': SymbolKind.Function, - 'generator': SymbolKind.Function, - 'class': SymbolKind.Class, - 'instance': SymbolKind.Class, - 'method': SymbolKind.Method, - 'builtin': SymbolKind.Class, - 'builtinfunction': SymbolKind.Function, - 'module': SymbolKind.Module, - 'file': SymbolKind.File, - 'xrange': SymbolKind.Array, - 'slice': SymbolKind.Class, - 'traceback': SymbolKind.Class, - 'frame': SymbolKind.Class, - 'buffer': SymbolKind.Array, - 'dictproxy': SymbolKind.Class, - 'funcdef': SymbolKind.Function, - 'property': SymbolKind.Property, - 'import': SymbolKind.Module, - 'keyword': SymbolKind.Variable, - 'constant': SymbolKind.Constant, - 'variable': SymbolKind.Variable, - 'value': SymbolKind.Variable, - 'param': SymbolKind.Variable, - 'statement': SymbolKind.Variable, - 'boolean': SymbolKind.Boolean, - 'int': SymbolKind.Number, - 'longlean': SymbolKind.Number, - 'float': SymbolKind.Number, - 'complex': SymbolKind.Number, - 'string': SymbolKind.String, - 'unicode': SymbolKind.String, - 'list': SymbolKind.Array, -} - - -def _kind(d): - """ Return the VSCode Symbol Type """ - return _SYMBOL_KIND_MAP.get(d.type) diff --git a/external-deps/python-language-server/pyls/plugins/yapf_format.py b/external-deps/python-language-server/pyls/plugins/yapf_format.py deleted file mode 100644 index 16afe97dc18..00000000000 --- a/external-deps/python-language-server/pyls/plugins/yapf_format.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import logging -import os -from yapf.yapflib import file_resources -from yapf.yapflib.yapf_api import FormatCode -from pyls import hookimpl - -log = logging.getLogger(__name__) - - -@hookimpl -def pyls_format_document(document): - return _format(document) - - -@hookimpl -def pyls_format_range(document, range): # pylint: disable=redefined-builtin - # First we 'round' the range up/down to full lines only - range['start']['character'] = 0 - range['end']['line'] += 1 - range['end']['character'] = 0 - - # From Yapf docs: - # lines: (list of tuples of integers) A list of tuples of lines, [start, end], - # that we want to format. The lines are 1-based indexed. It can be used by - # third-party code (e.g., IDEs) when reformatting a snippet of code rather - # than a whole file. - - # Add 1 for 1-indexing vs LSP's 0-indexing - lines = [(range['start']['line'] + 1, range['end']['line'] + 1)] - return _format(document, lines=lines) - - -def _format(document, lines=None): - new_source, changed = FormatCode( - document.source, - lines=lines, - filename=document.filename, - style_config=file_resources.GetDefaultStyleForDir( - os.path.dirname(document.path) - ) - ) - - if not changed: - return [] - - # I'm too lazy at the moment to parse diffs into TextEdit items - # So let's just return the entire file... - return [{ - 'range': { - 'start': {'line': 0, 'character': 0}, - # End char 0 of the line after our document - 'end': {'line': len(document.lines), 'character': 0} - }, - 'newText': new_source - }] diff --git a/external-deps/python-language-server/pyls/python_ls.py b/external-deps/python-language-server/pyls/python_ls.py deleted file mode 100644 index 577675f7441..00000000000 --- a/external-deps/python-language-server/pyls/python_ls.py +++ /dev/null @@ -1,412 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -from functools import partial -import logging -import os -import socketserver -import threading - -from pyls_jsonrpc.dispatchers import MethodDispatcher -from pyls_jsonrpc.endpoint import Endpoint -from pyls_jsonrpc.streams import JsonRpcStreamReader, JsonRpcStreamWriter - -from . import lsp, _utils, uris -from .config import config -from .workspace import Workspace - -log = logging.getLogger(__name__) - - -LINT_DEBOUNCE_S = 0.5 # 500 ms -PARENT_PROCESS_WATCH_INTERVAL = 10 # 10 s -MAX_WORKERS = 64 -PYTHON_FILE_EXTENSIONS = ('.py', '.pyi') -CONFIG_FILEs = ('pycodestyle.cfg', 'setup.cfg', 'tox.ini', '.flake8') - - -class _StreamHandlerWrapper(socketserver.StreamRequestHandler, object): - """A wrapper class that is used to construct a custom handler class.""" - - delegate = None - - def setup(self): - super(_StreamHandlerWrapper, self).setup() - # pylint: disable=no-member - self.delegate = self.DELEGATE_CLASS(self.rfile, self.wfile) - - def handle(self): - try: - self.delegate.start() - except OSError as e: - if os.name == 'nt': - # Catch and pass on ConnectionResetError when parent process - # dies - # pylint: disable=no-member, undefined-variable - if isinstance(e, WindowsError) and e.winerror == 10054: - pass - - # pylint: disable=no-member - self.SHUTDOWN_CALL() - - -def start_tcp_lang_server(bind_addr, port, check_parent_process, handler_class): - if not issubclass(handler_class, PythonLanguageServer): - raise ValueError('Handler class must be an instance of PythonLanguageServer') - - def shutdown_server(*args): - # pylint: disable=unused-argument - log.debug('Shutting down server') - # Shutdown call must be done on a thread, to prevent deadlocks - stop_thread = threading.Thread(target=server.shutdown) - stop_thread.start() - - # Construct a custom wrapper class around the user's handler_class - wrapper_class = type( - handler_class.__name__ + 'Handler', - (_StreamHandlerWrapper,), - {'DELEGATE_CLASS': partial(handler_class, - check_parent_process=check_parent_process), - 'SHUTDOWN_CALL': shutdown_server} - ) - - server = socketserver.TCPServer((bind_addr, port), wrapper_class, bind_and_activate=False) - server.allow_reuse_address = True - - try: - server.server_bind() - server.server_activate() - log.info('Serving %s on (%s, %s)', handler_class.__name__, bind_addr, port) - server.serve_forever() - finally: - log.info('Shutting down') - server.server_close() - - -def start_io_lang_server(rfile, wfile, check_parent_process, handler_class): - if not issubclass(handler_class, PythonLanguageServer): - raise ValueError('Handler class must be an instance of PythonLanguageServer') - log.info('Starting %s IO language server', handler_class.__name__) - server = handler_class(rfile, wfile, check_parent_process) - server.start() - - -class PythonLanguageServer(MethodDispatcher): - """ Implementation of the Microsoft VSCode Language Server Protocol - https://github.com/Microsoft/language-server-protocol/blob/master/versions/protocol-1-x.md - """ - - # pylint: disable=too-many-public-methods,redefined-builtin - - def __init__(self, rx, tx, check_parent_process=False): - self.workspace = None - self.config = None - self.root_uri = None - self.watching_thread = None - self.workspaces = {} - self.uri_workspace_mapper = {} - - self._jsonrpc_stream_reader = JsonRpcStreamReader(rx) - self._jsonrpc_stream_writer = JsonRpcStreamWriter(tx) - self._check_parent_process = check_parent_process - self._endpoint = Endpoint(self, self._jsonrpc_stream_writer.write, max_workers=MAX_WORKERS) - self._dispatchers = [] - self._shutdown = False - - def start(self): - """Entry point for the server.""" - self._jsonrpc_stream_reader.listen(self._endpoint.consume) - - def __getitem__(self, item): - """Override getitem to fallback through multiple dispatchers.""" - if self._shutdown and item != 'exit': - # exit is the only allowed method during shutdown - log.debug("Ignoring non-exit method during shutdown: %s", item) - raise KeyError - - try: - return super(PythonLanguageServer, self).__getitem__(item) - except KeyError: - # Fallback through extra dispatchers - for dispatcher in self._dispatchers: - try: - return dispatcher[item] - except KeyError: - continue - - raise KeyError() - - def m_shutdown(self, **_kwargs): - self._shutdown = True - return None - - def m_exit(self, **_kwargs): - self._endpoint.shutdown() - self._jsonrpc_stream_reader.close() - self._jsonrpc_stream_writer.close() - - def _match_uri_to_workspace(self, uri): - workspace_uri = _utils.match_uri_to_workspace(uri, self.workspaces) - return self.workspaces.get(workspace_uri, self.workspace) - - def _hook(self, hook_name, doc_uri=None, **kwargs): - """Calls hook_name and returns a list of results from all registered handlers""" - workspace = self._match_uri_to_workspace(doc_uri) - doc = workspace.get_document(doc_uri) if doc_uri else None - hook_handlers = self.config.plugin_manager.subset_hook_caller(hook_name, self.config.disabled_plugins) - return hook_handlers(config=self.config, workspace=workspace, document=doc, **kwargs) - - def capabilities(self): - server_capabilities = { - 'codeActionProvider': True, - 'codeLensProvider': { - 'resolveProvider': False, # We may need to make this configurable - }, - 'completionProvider': { - 'resolveProvider': False, # We know everything ahead of time - 'triggerCharacters': ['.'] - }, - 'documentFormattingProvider': True, - 'documentHighlightProvider': True, - 'documentRangeFormattingProvider': True, - 'documentSymbolProvider': True, - 'definitionProvider': True, - 'executeCommandProvider': { - 'commands': flatten(self._hook('pyls_commands')) - }, - 'hoverProvider': True, - 'referencesProvider': True, - 'renameProvider': True, - 'foldingRangeProvider': True, - 'signatureHelpProvider': { - 'triggerCharacters': ['(', ',', '='] - }, - 'textDocumentSync': { - 'change': lsp.TextDocumentSyncKind.INCREMENTAL, - 'save': { - 'includeText': True, - }, - 'openClose': True, - }, - 'workspace': { - 'workspaceFolders': { - 'supported': True, - 'changeNotifications': True - } - }, - 'experimental': merge(self._hook('pyls_experimental_capabilities')) - } - log.info('Server capabilities: %s', server_capabilities) - return server_capabilities - - def m_initialize(self, processId=None, rootUri=None, rootPath=None, initializationOptions=None, **_kwargs): - log.debug('Language server initialized with %s %s %s %s', processId, rootUri, rootPath, initializationOptions) - if rootUri is None: - rootUri = uris.from_fs_path(rootPath) if rootPath is not None else '' - - self.workspaces.pop(self.root_uri, None) - self.root_uri = rootUri - self.config = config.Config(rootUri, initializationOptions or {}, - processId, _kwargs.get('capabilities', {})) - self.workspace = Workspace(rootUri, self._endpoint, self.config) - self.workspaces[rootUri] = self.workspace - self._dispatchers = self._hook('pyls_dispatchers') - self._hook('pyls_initialize') - - if self._check_parent_process and processId is not None and self.watching_thread is None: - def watch_parent_process(pid): - # exit when the given pid is not alive - if not _utils.is_process_alive(pid): - log.info("parent process %s is not alive, exiting!", pid) - self.m_exit() - else: - threading.Timer(PARENT_PROCESS_WATCH_INTERVAL, watch_parent_process, args=[pid]).start() - - self.watching_thread = threading.Thread(target=watch_parent_process, args=(processId,)) - self.watching_thread.daemon = True - self.watching_thread.start() - # Get our capabilities - return {'capabilities': self.capabilities()} - - def m_initialized(self, **_kwargs): - self._hook('pyls_initialized') - - def code_actions(self, doc_uri, range, context): - return flatten(self._hook('pyls_code_actions', doc_uri, range=range, context=context)) - - def code_lens(self, doc_uri): - return flatten(self._hook('pyls_code_lens', doc_uri)) - - def completions(self, doc_uri, position): - completions = self._hook('pyls_completions', doc_uri, position=position) - return { - 'isIncomplete': False, - 'items': flatten(completions) - } - - def definitions(self, doc_uri, position): - return flatten(self._hook('pyls_definitions', doc_uri, position=position)) - - def document_symbols(self, doc_uri): - return flatten(self._hook('pyls_document_symbols', doc_uri)) - - def execute_command(self, command, arguments): - return self._hook('pyls_execute_command', command=command, arguments=arguments) - - def format_document(self, doc_uri): - return self._hook('pyls_format_document', doc_uri) - - def format_range(self, doc_uri, range): - return self._hook('pyls_format_range', doc_uri, range=range) - - def highlight(self, doc_uri, position): - return flatten(self._hook('pyls_document_highlight', doc_uri, position=position)) or None - - def hover(self, doc_uri, position): - return self._hook('pyls_hover', doc_uri, position=position) or {'contents': ''} - - @_utils.debounce(LINT_DEBOUNCE_S, keyed_by='doc_uri') - def lint(self, doc_uri, is_saved): - # Since we're debounced, the document may no longer be open - workspace = self._match_uri_to_workspace(doc_uri) - if doc_uri in workspace.documents: - workspace.publish_diagnostics( - doc_uri, - flatten(self._hook('pyls_lint', doc_uri, is_saved=is_saved)) - ) - - def references(self, doc_uri, position, exclude_declaration): - return flatten(self._hook( - 'pyls_references', doc_uri, position=position, - exclude_declaration=exclude_declaration - )) - - def rename(self, doc_uri, position, new_name): - return self._hook('pyls_rename', doc_uri, position=position, new_name=new_name) - - def signature_help(self, doc_uri, position): - return self._hook('pyls_signature_help', doc_uri, position=position) - - def folding(self, doc_uri): - return self._hook('pyls_folding_range', doc_uri) - - def m_text_document__did_close(self, textDocument=None, **_kwargs): - workspace = self._match_uri_to_workspace(textDocument['uri']) - workspace.rm_document(textDocument['uri']) - - def m_text_document__did_open(self, textDocument=None, **_kwargs): - workspace = self._match_uri_to_workspace(textDocument['uri']) - workspace.put_document(textDocument['uri'], textDocument['text'], version=textDocument.get('version')) - self._hook('pyls_document_did_open', textDocument['uri']) - self.lint(textDocument['uri'], is_saved=True) - - def m_text_document__did_change(self, contentChanges=None, textDocument=None, **_kwargs): - workspace = self._match_uri_to_workspace(textDocument['uri']) - for change in contentChanges: - workspace.update_document( - textDocument['uri'], - change, - version=textDocument.get('version') - ) - self.lint(textDocument['uri'], is_saved=False) - - def m_text_document__did_save(self, textDocument=None, **_kwargs): - self.lint(textDocument['uri'], is_saved=True) - - def m_text_document__code_action(self, textDocument=None, range=None, context=None, **_kwargs): - return self.code_actions(textDocument['uri'], range, context) - - def m_text_document__code_lens(self, textDocument=None, **_kwargs): - return self.code_lens(textDocument['uri']) - - def m_text_document__completion(self, textDocument=None, position=None, **_kwargs): - return self.completions(textDocument['uri'], position) - - def m_text_document__definition(self, textDocument=None, position=None, **_kwargs): - return self.definitions(textDocument['uri'], position) - - def m_text_document__document_highlight(self, textDocument=None, position=None, **_kwargs): - return self.highlight(textDocument['uri'], position) - - def m_text_document__hover(self, textDocument=None, position=None, **_kwargs): - return self.hover(textDocument['uri'], position) - - def m_text_document__document_symbol(self, textDocument=None, **_kwargs): - return self.document_symbols(textDocument['uri']) - - def m_text_document__formatting(self, textDocument=None, _options=None, **_kwargs): - # For now we're ignoring formatting options. - return self.format_document(textDocument['uri']) - - def m_text_document__rename(self, textDocument=None, position=None, newName=None, **_kwargs): - return self.rename(textDocument['uri'], position, newName) - - def m_text_document__folding_range(self, textDocument=None, **_kwargs): - return self.folding(textDocument['uri']) - - def m_text_document__range_formatting(self, textDocument=None, range=None, _options=None, **_kwargs): - # Again, we'll ignore formatting options for now. - return self.format_range(textDocument['uri'], range) - - def m_text_document__references(self, textDocument=None, position=None, context=None, **_kwargs): - exclude_declaration = not context['includeDeclaration'] - return self.references(textDocument['uri'], position, exclude_declaration) - - def m_text_document__signature_help(self, textDocument=None, position=None, **_kwargs): - return self.signature_help(textDocument['uri'], position) - - def m_workspace__did_change_configuration(self, settings=None): - self.config.update((settings or {}).get('pyls', {})) - for workspace_uri in self.workspaces: - workspace = self.workspaces[workspace_uri] - workspace.update_config(self.config) - for doc_uri in workspace.documents: - self.lint(doc_uri, is_saved=False) - - def m_workspace__did_change_workspace_folders(self, added=None, removed=None, **_kwargs): - for removed_info in removed: - removed_uri = removed_info['uri'] - self.workspaces.pop(removed_uri) - - for added_info in added: - added_uri = added_info['uri'] - self.workspaces[added_uri] = Workspace(added_uri, self._endpoint, self.config) - - # Migrate documents that are on the root workspace and have a better - # match now - doc_uris = list(self.workspace._docs.keys()) - for uri in doc_uris: - doc = self.workspace._docs.pop(uri) - new_workspace = self._match_uri_to_workspace(uri) - new_workspace._docs[uri] = doc - - def m_workspace__did_change_watched_files(self, changes=None, **_kwargs): - changed_py_files = set() - config_changed = False - for d in (changes or []): - if d['uri'].endswith(PYTHON_FILE_EXTENSIONS): - changed_py_files.add(d['uri']) - elif d['uri'].endswith(CONFIG_FILEs): - config_changed = True - - if config_changed: - self.config.settings.cache_clear() - elif not changed_py_files: - # Only externally changed python files and lint configs may result in changed diagnostics. - return - - for workspace_uri in self.workspaces: - workspace = self.workspaces[workspace_uri] - for doc_uri in workspace.documents: - # Changes in doc_uri are already handled by m_text_document__did_save - if doc_uri not in changed_py_files: - self.lint(doc_uri, is_saved=False) - - def m_workspace__execute_command(self, command=None, arguments=None): - return self.execute_command(command, arguments) - - -def flatten(list_of_lists): - return [item for lst in list_of_lists for item in lst] - - -def merge(list_of_dicts): - return {k: v for dictionary in list_of_dicts for k, v in dictionary.items()} diff --git a/external-deps/python-language-server/pyls/uris.py b/external-deps/python-language-server/pyls/uris.py deleted file mode 100644 index 7299ac9f654..00000000000 --- a/external-deps/python-language-server/pyls/uris.py +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -"""A collection of URI utilities with logic built on the VSCode URI library. - -https://github.com/Microsoft/vscode-uri/blob/e59cab84f5df6265aed18ae5f43552d3eef13bb9/lib/index.ts -""" -import re -from urllib import parse -from pyls import IS_WIN - -RE_DRIVE_LETTER_PATH = re.compile(r'^\/[a-zA-Z]:') - - -def urlparse(uri): - """Parse and decode the parts of a URI.""" - scheme, netloc, path, params, query, fragment = parse.urlparse(uri) - return ( - parse.unquote(scheme), - parse.unquote(netloc), - parse.unquote(path), - parse.unquote(params), - parse.unquote(query), - parse.unquote(fragment) - ) - - -def urlunparse(parts): - """Unparse and encode parts of a URI.""" - scheme, netloc, path, params, query, fragment = parts - - # Avoid encoding the windows drive letter colon - if RE_DRIVE_LETTER_PATH.match(path): - quoted_path = path[:3] + parse.quote(path[3:]) - else: - quoted_path = parse.quote(path) - - return parse.urlunparse(( - parse.quote(scheme), - parse.quote(netloc), - quoted_path, - parse.quote(params), - parse.quote(query), - parse.quote(fragment) - )) - - -def to_fs_path(uri): - """Returns the filesystem path of the given URI. - - Will handle UNC paths and normalize windows drive letters to lower-case. Also - uses the platform specific path separator. Will *not* validate the path for - invalid characters and semantics. Will *not* look at the scheme of this URI. - """ - # scheme://netloc/path;parameters?query#fragment - scheme, netloc, path, _params, _query, _fragment = urlparse(uri) - - if netloc and path and scheme == 'file': - # unc path: file://shares/c$/far/boo - value = "//{}{}".format(netloc, path) - - elif RE_DRIVE_LETTER_PATH.match(path): - # windows drive letter: file:///C:/far/boo - value = path[1].lower() + path[2:] - - else: - # Other path - value = path - - if IS_WIN: - value = value.replace('/', '\\') - - return value - - -def from_fs_path(path): - """Returns a URI for the given filesystem path.""" - scheme = 'file' - params, query, fragment = '', '', '' - path, netloc = _normalize_win_path(path) - return urlunparse((scheme, netloc, path, params, query, fragment)) - - -def uri_with(uri, scheme=None, netloc=None, path=None, params=None, query=None, fragment=None): - """Return a URI with the given part(s) replaced. - - Parts are decoded / encoded. - """ - old_scheme, old_netloc, old_path, old_params, old_query, old_fragment = urlparse(uri) - path, _netloc = _normalize_win_path(path) - return urlunparse(( - scheme or old_scheme, - netloc or old_netloc, - path or old_path, - params or old_params, - query or old_query, - fragment or old_fragment - )) - - -def _normalize_win_path(path): - netloc = '' - - # normalize to fwd-slashes on windows, - # on other systems bwd-slaches are valid - # filename character, eg /f\oo/ba\r.txt - if IS_WIN: - path = path.replace('\\', '/') - - # check for authority as used in UNC shares - # or use the path as given - if path[:2] == '//': - idx = path.index('/', 2) - if idx == -1: - netloc = path[2:] - else: - netloc = path[2:idx] - path = path[idx:] - else: - path = path - - # Ensure that path starts with a slash - # or that it is at least a slash - if not path.startswith('/'): - path = '/' + path - - # Normalize drive paths to lower case - if RE_DRIVE_LETTER_PATH.match(path): - path = path[0] + path[1].lower() + path[2:] - - return path, netloc diff --git a/external-deps/python-language-server/pyls/workspace.py b/external-deps/python-language-server/pyls/workspace.py deleted file mode 100644 index a58b76a21a3..00000000000 --- a/external-deps/python-language-server/pyls/workspace.py +++ /dev/null @@ -1,270 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import io -import logging -import os -import re - -import jedi - -from . import lsp, uris, _utils - -log = logging.getLogger(__name__) - -# 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]*') - - -class Workspace(object): - - M_PUBLISH_DIAGNOSTICS = 'textDocument/publishDiagnostics' - M_APPLY_EDIT = 'workspace/applyEdit' - M_SHOW_MESSAGE = 'window/showMessage' - - def __init__(self, root_uri, endpoint, config=None): - self._config = config - self._root_uri = root_uri - self._endpoint = endpoint - self._root_uri_scheme = uris.urlparse(self._root_uri)[0] - self._root_path = uris.to_fs_path(self._root_uri) - self._docs = {} - - # Cache jedi environments - self._environments = {} - - # Whilst incubating, keep rope private - self.__rope = None - self.__rope_config = None - - def _rope_project_builder(self, rope_config): - from rope.base.project import Project - - # TODO: we could keep track of dirty files and validate only those - if self.__rope is None or self.__rope_config != rope_config: - rope_folder = rope_config.get('ropeFolder') - self.__rope = Project(self._root_path, ropefolder=rope_folder) - self.__rope.prefs.set('extension_modules', rope_config.get('extensionModules', [])) - self.__rope.prefs.set('ignore_syntax_errors', True) - self.__rope.prefs.set('ignore_bad_imports', True) - self.__rope.validate() - return self.__rope - - @property - def documents(self): - return self._docs - - @property - def root_path(self): - return self._root_path - - @property - def root_uri(self): - return self._root_uri - - def is_local(self): - return (self._root_uri_scheme == '' or self._root_uri_scheme == 'file') and os.path.exists(self._root_path) - - def get_document(self, doc_uri): - """Return a managed document if-present, else create one pointing at disk. - - See https://github.com/Microsoft/language-server-protocol/issues/177 - """ - return self._docs.get(doc_uri) or self._create_document(doc_uri) - - def put_document(self, doc_uri, source, version=None): - self._docs[doc_uri] = self._create_document(doc_uri, source=source, version=version) - - def rm_document(self, doc_uri): - self._docs.pop(doc_uri) - - def update_document(self, doc_uri, change, version=None): - self._docs[doc_uri].apply_change(change) - self._docs[doc_uri].version = version - - def update_config(self, config): - self._config = config - for doc_uri in self.documents: - self.get_document(doc_uri).update_config(config) - - def apply_edit(self, edit): - return self._endpoint.request(self.M_APPLY_EDIT, {'edit': edit}) - - def publish_diagnostics(self, doc_uri, diagnostics): - self._endpoint.notify(self.M_PUBLISH_DIAGNOSTICS, params={'uri': doc_uri, 'diagnostics': diagnostics}) - - def show_message(self, message, msg_type=lsp.MessageType.Info): - self._endpoint.notify(self.M_SHOW_MESSAGE, params={'type': msg_type, 'message': message}) - - def source_roots(self, document_path): - """Return the source roots for the given document.""" - files = _utils.find_parents(self._root_path, document_path, ['setup.py', 'pyproject.toml']) or [] - return list(set((os.path.dirname(project_file) for project_file in files))) or [self._root_path] - - def _create_document(self, doc_uri, source=None, version=None): - path = uris.to_fs_path(doc_uri) - return Document( - doc_uri, source=source, version=version, - extra_sys_path=self.source_roots(path), - rope_project_builder=self._rope_project_builder, - config=self._config, workspace=self, - ) - - -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): - self.uri = uri - self.version = version - self.path = uris.to_fs_path(uri) - self.filename = os.path.basename(self.path) - - self._config = config - self._workspace = workspace - self._local = local - self._source = source - self._extra_sys_path = extra_sys_path or [] - self._rope_project_builder = rope_project_builder - - def __str__(self): - return str(self.uri) - - def _rope_resource(self, rope_config): - from rope.base import libutils - return libutils.path_to_resource(self._rope_project_builder(rope_config), self.path) - - @property - def lines(self): - return self.source.splitlines(True) - - @property - def source(self): - if self._source is None: - with io.open(self.path, 'r', encoding='utf-8') as f: - return f.read() - return self._source - - def update_config(self, config): - self._config = config - - def apply_change(self, change): - """Apply a change to the document.""" - text = change['text'] - change_range = change.get('range') - - if not change_range: - # The whole file has changed - self._source = text - return - - start_line = change_range['start']['line'] - start_col = change_range['start']['character'] - end_line = change_range['end']['line'] - end_col = change_range['end']['character'] - - # Check for an edit occuring at the very end of the file - if start_line == len(self.lines): - self._source = self.source + text - return - - new = io.StringIO() - - # Iterate over the existing document until we hit the edit range, - # at which point we write the new text, then loop until we hit - # the end of the range and continue writing. - for i, line in enumerate(self.lines): - if i < start_line: - new.write(line) - continue - - if i > end_line: - new.write(line) - continue - - if i == start_line: - new.write(line[:start_col]) - new.write(text) - - if i == end_line: - new.write(line[end_col:]) - - self._source = new.getvalue() - - def offset_at_position(self, position): - """Return the byte-offset pointed at by the given position.""" - return position['character'] + len(''.join(self.lines[:position['line']])) - - def word_at_position(self, position): - """Get the word under the cursor returning the start and end positions.""" - if position['line'] >= len(self.lines): - return '' - - line = self.lines[position['line']] - i = position['character'] - # Split word in two - start = line[:i] - end = line[i:] - - # Take end of start and start of end to find word - # These are guaranteed to match, even if they match the empty string - m_start = RE_START_WORD.findall(start) - m_end = RE_END_WORD.findall(end) - - 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, - ) - - def jedi_script(self, position=None): - extra_paths = [] - environment_path = None - - if self._config: - jedi_settings = self._config.plugin_settings('jedi', document_path=self.path) - 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 - - kwargs = { - 'source': self.source, - 'path': self.path, - 'sys_path': sys_path, - 'environment': environment, - } - - 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): - # TODO(gatesn): #339 - make better use of jedi environments, they seem pretty powerful - if environment_path is None: - environment = jedi.api.environment.get_cached_default_environment() - else: - if environment_path in self._workspace._environments: - environment = self._workspace._environments[environment_path] - else: - environment = jedi.api.environment.create_environment(path=environment_path, safe=False) - self._workspace._environments[environment_path] = environment - - return environment - - def sys_path(self, environment_path=None): - # Copy our extra sys path - path = list(self._extra_sys_path) - environment = self.get_enviroment(environment_path=environment_path) - path.extend(environment.get_sys_path()) - return path diff --git a/external-deps/python-language-server/resources/auto-complete.gif b/external-deps/python-language-server/resources/auto-complete.gif deleted file mode 100644 index 6c4fe4ff0603063f89ce6002525e7c90ee9da10e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55532 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 diff --git a/external-deps/python-language-server/resources/document-format.gif b/external-deps/python-language-server/resources/document-format.gif deleted file mode 100644 index c68f89a1b79d143215c08e6caf3a46cc70d29de7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66169 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

dQQATq#F6kms`?=H0 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 diff --git a/external-deps/python-language-server/resources/document-symbols.gif b/external-deps/python-language-server/resources/document-symbols.gif deleted file mode 100644 index 1d9601d6df7a1fa7d4eb93812c5f7bbd0cc7f2e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37353 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

_>Chh3g1ru)i9~q37 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 diff --git a/external-deps/python-language-server/resources/hover.gif b/external-deps/python-language-server/resources/hover.gif deleted file mode 100644 index cb2bc86dde8713cf01488374f50aa278876f5ff9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36464 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%0Dv&@F;VKfHe!=EX` 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�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

0jn467e&G*1Tga~r(P0S%TH-p=;zF%&YlS`> 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 O8epBl#KgkIU=09f-c^wR diff --git a/external-deps/python-language-server/resources/linting.gif b/external-deps/python-language-server/resources/linting.gif deleted file mode 100644 index 153f652e708893a21c8cdddf612ac341c4c248c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30013 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 PO?AYEW^%L`;Nt%Qy@$Mo diff --git a/external-deps/python-language-server/resources/signature-help.gif b/external-deps/python-language-server/resources/signature-help.gif deleted file mode 100644 index 5e48433890e5b90fb1f60a66e6eb3dc358624d1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10586 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 diff --git a/external-deps/python-language-server/scripts/circle/pypi.sh b/external-deps/python-language-server/scripts/circle/pypi.sh deleted file mode 100755 index d0eae1be0bb..00000000000 --- a/external-deps/python-language-server/scripts/circle/pypi.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -e - -if [ -z "$CI" ]; then - echo "Will only continue on CI" - exit -fi - -# build package and upload to private pypi index -rm -f ~/.pypirc -echo "[distutils]" >> ~/.pypirc -echo "index-servers = pypi-private" >> ~/.pypirc -echo "[pypi-private]" >> ~/.pypirc -echo "repository=https://$PYPI_HOST" >> ~/.pypirc -echo "username=$PYPI_USERNAME" >> ~/.pypirc -echo "password=$PYPI_PASSWORD" >> ~/.pypirc - -python setup.py bdist_wheel sdist upload -r pypi-private diff --git a/external-deps/python-language-server/setup.cfg b/external-deps/python-language-server/setup.cfg deleted file mode 100644 index c2bb1ae8afd..00000000000 --- a/external-deps/python-language-server/setup.cfg +++ /dev/null @@ -1,18 +0,0 @@ -[versioneer] -VCS = git -style = pep440 -versionfile_source = pyls/_version.py -versionfile_build = pyls/_version.py -tag_prefix = -parentdir_prefix = - -[pycodestyle] -ignore = E226, E722, W504 -max-line-length = 120 -exclude = test/plugins/.ropeproject,test/.ropeproject - -[tool:pytest] -testpaths = test -addopts = - --cov-report html --cov-report term --junitxml=pytest.xml - --cov pyls --cov test diff --git a/external-deps/python-language-server/setup.py b/external-deps/python-language-server/setup.py deleted file mode 100755 index f1ddef5e341..00000000000 --- a/external-deps/python-language-server/setup.py +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env python -from setuptools import find_packages, setup -import versioneer - -README = open('README.rst', 'r').read() - - -setup( - name='python-language-server', - - # Versions should comply with PEP440. For a discussion on single-sourcing - # the version across setup.py and the project code, see - # https://packaging.python.org/en/latest/single_source_version.html - version=versioneer.get_version(), - cmdclass=versioneer.get_cmdclass(), - - description='Python Language Server for the Language Server Protocol', - - long_description=README, - - # The project's main homepage. - url='https://github.com/palantir/python-language-server', - - author='Palantir Technologies, Inc.', - - # You can just specify the packages manually here if your project is - # simple. Or you can use find_packages(). - packages=find_packages(exclude=['contrib', 'docs', 'test', 'test.*']), - - # List run-time dependencies here. These will be installed by pip when - # your project is installed. For an analysis of "install_requires" vs pip's - # requirements files see: - # https://packaging.python.org/en/latest/requirements.html - install_requires=[ - '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', - 'python-jsonrpc-server>=0.3.2', - 'pluggy', - 'ujson<=1.35; platform_system!="Windows"' - ], - - # List additional groups of dependencies here (e.g. development - # dependencies). You can install these using the following syntax, - # for example: - # $ pip install -e .[test] - extras_require={ - 'all': [ - 'autopep8', - 'flake8', - 'mccabe', - 'pycodestyle', - 'pydocstyle>=2.0.0', - 'pyflakes>=1.6.0,<2.2.0', - 'pylint', - 'rope>=0.10.5', - 'yapf', - ], - 'autopep8': ['autopep8'], - 'flake8': ['flake8'], - 'mccabe': ['mccabe'], - 'pycodestyle': ['pycodestyle'], - 'pydocstyle': ['pydocstyle>=2.0.0'], - 'pyflakes': ['pyflakes>=1.6.0,<2.2.0'], - 'pylint': ['pylint'], - 'rope': ['rope>0.10.5'], - 'yapf': ['yapf'], - 'test': ['versioneer', 'pylint', 'pytest', 'mock', 'pytest-cov', - 'coverage', 'numpy', 'pandas', 'matplotlib', - 'pyqt5;python_version>="3"'], - }, - - # To provide executable scripts, use entry points in preference to the - # "scripts" keyword. Entry points provide cross-platform support and allow - # pip to create the appropriate form of executable for the target platform. - entry_points={ - 'console_scripts': [ - 'pyls = pyls.__main__:main', - ], - 'pyls': [ - 'autopep8 = pyls.plugins.autopep8_format', - 'folding = pyls.plugins.folding', - 'flake8 = pyls.plugins.flake8_lint', - 'jedi_completion = pyls.plugins.jedi_completion', - 'jedi_definition = pyls.plugins.definition', - 'jedi_hover = pyls.plugins.hover', - 'jedi_highlight = pyls.plugins.highlight', - 'jedi_references = pyls.plugins.references', - 'jedi_signature_help = pyls.plugins.signature', - 'jedi_symbols = pyls.plugins.symbols', - 'mccabe = pyls.plugins.mccabe_lint', - 'preload = pyls.plugins.preload_imports', - 'pycodestyle = pyls.plugins.pycodestyle_lint', - 'pydocstyle = pyls.plugins.pydocstyle_lint', - 'pyflakes = pyls.plugins.pyflakes_lint', - 'pylint = pyls.plugins.pylint_lint', - 'rope_completion = pyls.plugins.rope_completion', - 'rope_rename = pyls.plugins.rope_rename', - 'yapf = pyls.plugins.yapf_format' - ] - }, -) diff --git a/external-deps/python-language-server/test/__init__.py b/external-deps/python-language-server/test/__init__.py deleted file mode 100644 index 8b18553c0b7..00000000000 --- a/external-deps/python-language-server/test/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import sys -import pytest -from pyls 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 --git a/external-deps/python-language-server/test/conftest.py b/external-deps/python-language-server/test/conftest.py deleted file mode 100644 index 59542dd209b..00000000000 --- a/external-deps/python-language-server/test/conftest.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -""" py.test configuration""" -import logging -from pyls.__main__ import LOG_FORMAT - -logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT) - - -pytest_plugins = [ - 'test.fixtures' -] diff --git a/external-deps/python-language-server/test/fixtures.py b/external-deps/python-language-server/test/fixtures.py deleted file mode 100644 index 4e915e17862..00000000000 --- a/external-deps/python-language-server/test/fixtures.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import sys -from mock import Mock -import pytest - -from pyls import uris -from pyls.config.config import Config -from pyls.python_ls import PythonLanguageServer -from pyls.workspace import Workspace, Document - -if sys.version_info[0] < 3: - from StringIO import StringIO -else: - from io import StringIO - -DOC_URI = uris.from_fs_path(__file__) -DOC = """import sys - -def main(): - print sys.stdin.read() -""" - - -@pytest.fixture -def pyls(tmpdir): - """ Return an initialized python LS """ - ls = PythonLanguageServer(StringIO, StringIO) - - ls.m_initialize( - processId=1, - rootUri=uris.from_fs_path(str(tmpdir)), - initializationOptions={} - ) - - return ls - - -@pytest.fixture -def workspace(tmpdir): - """Return a workspace.""" - return Workspace(uris.from_fs_path(str(tmpdir)), Mock()) - - -@pytest.fixture -def config(workspace): # pylint: disable=redefined-outer-name - """Return a config object.""" - return Config(workspace.root_uri, {}, 0, {}) - - -@pytest.fixture -def doc(): - return Document(DOC_URI, DOC) diff --git a/external-deps/python-language-server/test/plugins/__init__.py b/external-deps/python-language-server/test/plugins/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/external-deps/python-language-server/test/plugins/test_autopep8_format.py b/external-deps/python-language-server/test/plugins/test_autopep8_format.py deleted file mode 100644 index 09c769aef1b..00000000000 --- a/external-deps/python-language-server/test/plugins/test_autopep8_format.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -from pyls import uris -from pyls.plugins.autopep8_format import pyls_format_document, pyls_format_range -from pyls.workspace import Document - -DOC_URI = uris.from_fs_path(__file__) -DOC = """a = 123 - - - - -def func(): - pass -""" - -GOOD_DOC = """A = ['hello', 'world']\n""" - - -def test_format(config): - doc = Document(DOC_URI, 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_range = { - 'start': {'line': 0, 'character': 0}, - 'end': {'line': 2, 'character': 0} - } - res = pyls_format_range(config, doc, def_range) - - assert len(res) == 1 - - # Make sure the func is still badly formatted - 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) - assert not pyls_format_document(config, doc) diff --git a/external-deps/python-language-server/test/plugins/test_completion.py b/external-deps/python-language-server/test/plugins/test_completion.py deleted file mode 100644 index 57caa8b3059..00000000000 --- a/external-deps/python-language-server/test/plugins/test_completion.py +++ /dev/null @@ -1,313 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -from distutils.version import LooseVersion -import os -import sys - -from test.test_utils import MockWorkspace -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 - - -PY2 = sys.version[0] == '2' -LINUX = sys.platform.startswith('linux') -CI = os.environ.get('CI') -LOCATION = os.path.realpath( - os.path.join(os.getcwd(), os.path.dirname(__file__)) -) -DOC_URI = uris.from_fs_path(__file__) -DOC = """import os -print os.path.isabs("/tmp") - -def hello(): - pass - -def _a_hello(): - pass - -class Hello(): - - @property - def world(self): - return None - - def everyone(self, a, b, c=None, d=2): - pass - -print Hello().world - -print Hello().every -""" - - -def test_rope_import_completion(config, workspace): - com_position = {'line': 0, 'character': 7} - doc = Document(DOC_URI, DOC) - items = pyls_rope_completions(config, workspace, doc, com_position) - assert items is None - - -def test_jedi_completion(config): - # Over 'i' in os.path.isabs(...) - com_position = {'line': 1, 'character': 15} - doc = Document(DOC_URI, DOC) - items = pyls_jedi_completions(config, doc, com_position) - - assert items - assert items[0]['label'] == 'isabs(path)' - - # Test we don't throw with big character - pyls_jedi_completions(config, doc, {'line': 1, 'character': 1000}) - - -def test_rope_completion(config, workspace): - # Over 'i' in os.path.isabs(...) - com_position = {'line': 1, 'character': 15} - workspace.put_document(DOC_URI, source=DOC) - doc = workspace.get_document(DOC_URI) - items = pyls_rope_completions(config, workspace, doc, com_position) - - assert items - assert items[0]['label'] == 'isabs' - - -def test_jedi_completion_ordering(config): - # Over the blank line - com_position = {'line': 8, 'character': 0} - doc = Document(DOC_URI, DOC) - completions = pyls_jedi_completions(config, doc, com_position) - - items = {c['label']: c['sortText'] for c in completions} - - # And that 'hidden' functions come after unhidden ones - assert items['hello()'] < items['_a_hello()'] - - -def test_jedi_property_completion(config): - # Over the 'w' in 'print Hello().world' - com_position = {'line': 18, 'character': 15} - doc = Document(DOC_URI, DOC) - completions = pyls_jedi_completions(config, doc, com_position) - - items = {c['label']: c['sortText'] for c in completions} - - # Ensure we can complete the 'world' property - assert 'world' in list(items.keys())[0] - - -def test_jedi_method_completion(config): - # Over the 'y' in 'print Hello().every' - com_position = {'line': 20, 'character': 19} - doc = Document(DOC_URI, DOC) - - config.capabilities['textDocument'] = {'completion': {'completionItem': {'snippetSupport': True}}} - config.update({'plugins': {'jedi_completion': {'include_params': True}}}) - - completions = pyls_jedi_completions(config, doc, com_position) - everyone_method = [completion for completion in completions if completion['label'] == 'everyone(a, b, c, d)'][0] - - # Ensure we only generate snippets for positional args - assert everyone_method['insertTextFormat'] == lsp.InsertTextFormat.Snippet - assert everyone_method['insertText'] == 'everyone(${1:a}, ${2:b})$0' - - # Disable param snippets - config.update({'plugins': {'jedi_completion': {'include_params': False}}}) - - completions = pyls_jedi_completions(config, doc, com_position) - everyone_method = [completion for completion in completions if completion['label'] == 'everyone(a, b, c, d)'][0] - - assert 'insertTextFormat' not in everyone_method - assert everyone_method['insertText'] == 'everyone' - - -@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): - # 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) - 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 - - -@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)} - doc = Document(DOC_URI, doc_numpy) - items = pyls_jedi_completions(config, doc, com_position) - - assert items - 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)} - doc = Document(DOC_URI, doc_pandas) - 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): - doc_mpl = "import matplotlib.pyplot as plt; plt." - com_position = {'line': 0, 'character': len(doc_mpl)} - doc = Document(DOC_URI, doc_mpl) - items = pyls_jedi_completions(config, doc, com_position) - - assert items - 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} - doc = Document(DOC_URI, doc_snippets) - config.capabilities['textDocument'] = { - 'completion': {'completionItem': {'snippetSupport': True}}} - config.update({'plugins': {'jedi_completion': {'include_params': True}}}) - completions = pyls_jedi_completions(config, doc, com_position) - assert completions[0]['insertText'] == 'defaultdict' - - com_position = {'line': 1, 'character': len(doc_snippets)} - completions = pyls_jedi_completions(config, doc, com_position) - assert completions[0]['insertText'] == 'defaultdict($0)' - - -def test_snippet_parsing(config): - doc = 'import numpy as np\nnp.logical_and' - completion_position = {'line': 1, 'character': 14} - doc = Document(DOC_URI, doc) - config.capabilities['textDocument'] = { - 'completion': {'completionItem': {'snippetSupport': True}}} - config.update({'plugins': {'jedi_completion': {'include_params': True}}}) - completions = pyls_jedi_completions(config, doc, completion_position) - out = 'logical_and(${1:x1}, ${2:x2})$0' - assert completions[0]['insertText'] == out - - -def test_multiline_import_snippets(config): - document = 'from datetime import(\n date,\n datetime)\na=date' - doc = Document(DOC_URI, document) - config.capabilities['textDocument'] = { - 'completion': {'completionItem': {'snippetSupport': True}}} - config.update({'plugins': {'jedi_completion': {'include_params': True}}}) - - position = {'line': 1, 'character': 5} - completions = pyls_jedi_completions(config, doc, position) - assert completions[0]['insertText'] == 'date' - - position = {'line': 2, 'character': 9} - completions = pyls_jedi_completions(config, doc, position) - assert completions[0]['insertText'] == 'datetime' - - -def test_multiline_snippets(config): - document = 'from datetime import\\\n date,\\\n datetime \na=date' - doc = Document(DOC_URI, document) - config.capabilities['textDocument'] = { - 'completion': {'completionItem': {'snippetSupport': True}}} - config.update({'plugins': {'jedi_completion': {'include_params': True}}}) - - position = {'line': 1, 'character': 5} - completions = pyls_jedi_completions(config, doc, position) - assert completions[0]['insertText'] == 'date' - - position = {'line': 2, 'character': 9} - completions = pyls_jedi_completions(config, doc, position) - assert completions[0]['insertText'] == 'datetime' - - -def test_multistatement_snippet(config): - 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) - 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) - 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): - # Create a tempfile with some content and pass to extra_paths - temp_doc_content = ''' -def spam(): - pass -''' - p = tmpdir.mkdir("extra_path") - extra_paths = [str(p)] - p = p.join("foo.py") - p.write(temp_doc_content) - - # Content of doc to test completion - doc_content = """import foo -foo.s""" - doc = Document(DOC_URI, doc_content) - - # After 'foo.s' without extra paths - com_position = {'line': 1, 'character': 5} - completions = pyls_jedi_completions(config, doc, com_position) - assert completions is None - - # Update config extra paths - config.update({'plugins': {'jedi': {'extra_paths': extra_paths}}}) - doc.update_config(config) - - # After 'foo.s' with extra paths - com_position = {'line': 1, 'character': 5} - completions = pyls_jedi_completions(config, doc, com_position) - assert completions[0]['label'] == 'spam()' - - -@pytest.mark.skipif(PY2 or not LINUX or not CI, reason="tested on linux and python 3 only") -def test_jedi_completion_environment(config): - # Content of doc to test completion - doc_content = '''import logh -''' - doc = Document(DOC_URI, doc_content, workspace=MockWorkspace()) - - # After 'import logh' with default environment - com_position = {'line': 0, 'character': 11} - - assert os.path.isdir('/tmp/pyenv/') - - config.update({'plugins': {'jedi': {'environment': None}}}) - doc.update_config(config) - completions = pyls_jedi_completions(config, doc, com_position) - assert completions is None - - # Update config extra environment - env_path = '/tmp/pyenv/bin/python' - config.update({'plugins': {'jedi': {'environment': env_path}}}) - doc.update_config(config) - - # After 'import logh' with new environment - completions = pyls_jedi_completions(config, doc, com_position) - assert completions[0]['label'] == 'loghub' - assert 'changelog generator' in completions[0]['documentation'].lower() diff --git a/external-deps/python-language-server/test/plugins/test_definitions.py b/external-deps/python-language-server/test/plugins/test_definitions.py deleted file mode 100644 index e2db9c6fd53..00000000000 --- a/external-deps/python-language-server/test/plugins/test_definitions.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -from pyls import uris -from pyls.plugins.definition import pyls_definitions -from pyls.workspace import Document - - -DOC_URI = uris.from_fs_path(__file__) -DOC = """def a(): - pass - -print a() - - -class Directory(object): - def __init__(self): - self.members = dict() - - def add_member(self, id, name): - self.members[id] = name -""" - - -def test_definitions(config): - # Over 'a' in print a - cursor_pos = {'line': 3, 'character': 6} - - # The definition of 'a' - def_range = { - 'start': {'line': 0, 'character': 4}, - 'end': {'line': 0, 'character': 5} - } - - doc = Document(DOC_URI, DOC) - assert [{'uri': DOC_URI, 'range': def_range}] == pyls_definitions(config, doc, cursor_pos) - - -def test_builtin_definition(config): - # Over 'i' in dict - cursor_pos = {'line': 8, 'character': 24} - - # No go-to def for builtins - doc = Document(DOC_URI, DOC) - assert not pyls_definitions(config, doc, cursor_pos) - - -def test_assignment(config): - # Over 's' in self.members[id] - cursor_pos = {'line': 11, 'character': 19} - - # The assignment of 'self.members' - def_range = { - 'start': {'line': 8, 'character': 13}, - 'end': {'line': 8, 'character': 20} - } - - doc = Document(DOC_URI, DOC) - assert [{'uri': DOC_URI, 'range': def_range}] == pyls_definitions(config, doc, cursor_pos) diff --git a/external-deps/python-language-server/test/plugins/test_flake8_lint.py b/external-deps/python-language-server/test/plugins/test_flake8_lint.py deleted file mode 100644 index d4858f8e352..00000000000 --- a/external-deps/python-language-server/test/plugins/test_flake8_lint.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2019 Palantir Technologies, Inc. -import tempfile -import os -from mock import patch - -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 - -t = "TEST" - -def using_const(): -\ta = 8 + 9 -\treturn t -""" - - -def temp_document(doc_text): - temp_file = tempfile.NamedTemporaryFile(mode='w', delete=False) - name = temp_file.name - temp_file.write(doc_text) - temp_file.close() - doc = Document(uris.from_fs_path(name)) - - return name, doc - - -def test_flake8_no_checked_file(config): - # 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) - diags = flake8_lint.pyls_lint(config, doc) - assert diags == [] - - -def test_flake8_lint(config): - try: - name, doc = temp_document(DOC) - diags = flake8_lint.pyls_lint(config, doc) - msg = 'local variable \'a\' is assigned to but never used' - unused_var = [d for d in diags if d['message'] == msg][0] - - assert unused_var['source'] == 'flake8' - assert unused_var['code'] == 'F841' - assert unused_var['range']['start'] == {'line': 5, 'character': 1} - assert unused_var['range']['end'] == {'line': 5, 'character': 11} - assert unused_var['severity'] == lsp.DiagnosticSeverity.Warning - - finally: - os.remove(name) - - -def test_flake8_config_param(config): - with patch('pyls.plugins.flake8_lint.Popen') as popen_mock: - flake8_conf = '/tmp/some.cfg' - config.update({'plugins': {'flake8': {'config': flake8_conf}}}) - _name, doc = temp_document(DOC) - flake8_lint.pyls_lint(config, doc) - call_args = popen_mock.call_args.args[0] - assert 'flake8' in call_args - assert '--config={}'.format(flake8_conf) in call_args diff --git a/external-deps/python-language-server/test/plugins/test_folding.py b/external-deps/python-language-server/test/plugins/test_folding.py deleted file mode 100644 index ec6dd316c39..00000000000 --- a/external-deps/python-language-server/test/plugins/test_folding.py +++ /dev/null @@ -1,168 +0,0 @@ -# Copyright 2019 Palantir Technologies, Inc. - -from textwrap import dedent - -from pyls import uris -from pyls.workspace import Document -from pyls.plugins.folding import pyls_folding_range - - -DOC_URI = uris.from_fs_path(__file__) -DOC = dedent(""" -def func(arg1, arg2, arg3, - arg4, arg5, default=func( - 2, 3, 4 - )): - return (2, 3, - 4, 5) - -@decorator( - param1, - param2 -) -def decorated_func(x, y, z): - if x: - return y - elif y: - return z - elif x + y > z: - return True - else: - return x - -class A(): - def method(self, x1): - def inner(): - return x1 - - if x2: - func(3, 4, 5, 6, - 7) - elif x3 < 2: - pass - else: - more_complex_func(2, 3, 4, 5, 6, - 8) - return inner - -a = 2 -operation = (a_large_variable_that_fills_all_space + - other_embarrasingly_long_variable - 2 * 3 / 5) - -(a, b, c, - d, e, f) = func(3, 4, 5, 6, - 7, 8, 9, 10) - -for i in range(0, 3): - i += 1 - while x < i: - expr = (2, 4) - a = func(expr + i, arg2, arg3, arg4, - arg5, var(2, 3, 4, - 5)) - for j in range(0, i): - if i % 2 == 1: - pass - -compren = [x for x in range(0, 3) - if x == 2] - -with open('doc', 'r') as f: - try: - f / 0 - except: - pass - finally: - raise SomeException() - -def testC(): - pass -""") - -SYNTAX_ERR = dedent(""" -def func(arg1, arg2, arg3, - arg4, arg5, default=func( - 2, 3, 4 - )): - return (2, 3, - 4, 5) - -class A(: - pass - -a = 2 -operation = (a_large_variable_that_fills_all_space + - other_embarrasingly_long_variable - 2 * 3 / - -(a, b, c, - d, e, f) = func(3, 4, 5, 6, - 7, 8, 9, 10 -a = 2 -for i in range(0, 3) - i += 1 - while x < i: - expr = (2, 4) - a = func(expr + i, arg2, arg3, arg4, - arg5, var(2, 3, 4, - 5)) - for j in range(0, i): - if i % 2 == 1: - pass -""") - - -def test_folding(): - doc = Document(DOC_URI, DOC) - ranges = pyls_folding_range(doc) - expected = [{'startLine': 1, 'endLine': 6}, - {'startLine': 2, 'endLine': 3}, - {'startLine': 5, 'endLine': 6}, - {'startLine': 8, 'endLine': 11}, - {'startLine': 12, 'endLine': 20}, - {'startLine': 13, 'endLine': 14}, - {'startLine': 15, 'endLine': 16}, - {'startLine': 17, 'endLine': 18}, - {'startLine': 19, 'endLine': 20}, - {'startLine': 22, 'endLine': 35}, - {'startLine': 23, 'endLine': 35}, - {'startLine': 24, 'endLine': 25}, - {'startLine': 27, 'endLine': 29}, - {'startLine': 28, 'endLine': 29}, - {'startLine': 30, 'endLine': 31}, - {'startLine': 32, 'endLine': 34}, - {'startLine': 33, 'endLine': 34}, - {'startLine': 38, 'endLine': 39}, - {'startLine': 41, 'endLine': 43}, - {'startLine': 42, 'endLine': 43}, - {'startLine': 45, 'endLine': 54}, - {'startLine': 47, 'endLine': 51}, - {'startLine': 49, 'endLine': 51}, - {'startLine': 50, 'endLine': 51}, - {'startLine': 52, 'endLine': 54}, - {'startLine': 53, 'endLine': 54}, - {'startLine': 56, 'endLine': 57}, - {'startLine': 59, 'endLine': 65}, - {'startLine': 60, 'endLine': 61}, - {'startLine': 62, 'endLine': 63}, - {'startLine': 64, 'endLine': 65}, - {'startLine': 67, 'endLine': 68}] - assert ranges == expected - - -def test_folding_syntax_error(): - doc = Document(DOC_URI, SYNTAX_ERR) - ranges = pyls_folding_range(doc) - expected = [{'startLine': 1, 'endLine': 6}, - {'startLine': 2, 'endLine': 3}, - {'startLine': 5, 'endLine': 6}, - {'startLine': 8, 'endLine': 9}, - {'startLine': 12, 'endLine': 13}, - {'startLine': 15, 'endLine': 17}, - {'startLine': 16, 'endLine': 17}, - {'startLine': 19, 'endLine': 28}, - {'startLine': 21, 'endLine': 25}, - {'startLine': 23, 'endLine': 25}, - {'startLine': 24, 'endLine': 25}, - {'startLine': 26, 'endLine': 28}, - {'startLine': 27, 'endLine': 28}] - assert ranges == expected diff --git a/external-deps/python-language-server/test/plugins/test_highlight.py b/external-deps/python-language-server/test/plugins/test_highlight.py deleted file mode 100644 index 41e9075be02..00000000000 --- a/external-deps/python-language-server/test/plugins/test_highlight.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -from pyls import lsp, uris -from pyls.workspace import Document -from pyls.plugins.highlight import pyls_document_highlight - - -DOC_URI = uris.from_fs_path(__file__) -DOC = """a = "hello" -a.startswith("b") -""" - - -def test_highlight(): - # Over 'a' in a.startswith - cursor_pos = {'line': 1, 'character': 0} - - doc = Document(DOC_URI, DOC) - assert pyls_document_highlight(doc, cursor_pos) == [{ - 'range': { - 'start': {'line': 0, 'character': 0}, - 'end': {'line': 0, 'character': 1}, - }, - # The first usage is Write - 'kind': lsp.DocumentHighlightKind.Write - }, { - 'range': { - 'start': {'line': 1, 'character': 0}, - 'end': {'line': 1, 'character': 1}, - }, - # The second usage is Read - 'kind': lsp.DocumentHighlightKind.Read - }] - - -SYS_DOC = '''import sys -print sys.path -''' - - -def test_sys_highlight(): - cursor_pos = {'line': 0, 'character': 8} - - doc = Document(DOC_URI, SYS_DOC) - assert pyls_document_highlight(doc, cursor_pos) == [{ - 'range': { - 'start': {'line': 0, 'character': 7}, - 'end': {'line': 0, 'character': 10} - }, - 'kind': lsp.DocumentHighlightKind.Write - }, { - 'range': { - 'start': {'line': 1, 'character': 6}, - 'end': {'line': 1, 'character': 9} - }, - 'kind': lsp.DocumentHighlightKind.Read - }] diff --git a/external-deps/python-language-server/test/plugins/test_hover.py b/external-deps/python-language-server/test/plugins/test_hover.py deleted file mode 100644 index 4ae29cd905e..00000000000 --- a/external-deps/python-language-server/test/plugins/test_hover.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -from distutils.version import LooseVersion - -from pyls import uris, _utils -from pyls.plugins.hover import pyls_hover -from pyls.workspace import Document - -DOC_URI = uris.from_fs_path(__file__) -DOC = """ - -def main(): - \"\"\"hello world\"\"\" - pass -""" - -NUMPY_DOC = """ - -import numpy as np -np.sin - -""" - - -def test_numpy_hover(): - # Over the blank line - no_hov_position = {'line': 1, 'character': 0} - # Over 'numpy' in import numpy as np - numpy_hov_position_1 = {'line': 2, 'character': 8} - # Over 'np' in import numpy as np - numpy_hov_position_2 = {'line': 2, 'character': 17} - # Over 'np' in np.sin - numpy_hov_position_3 = {'line': 3, 'character': 1} - # Over 'sin' in np.sin - numpy_sin_hov_position = {'line': 3, 'character': 4} - - 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 = '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_3)['contents'][0] - - contents = 'Trigonometric sine, element-wise.\n\n' - assert contents in pyls_hover( - doc, numpy_sin_hov_position)['contents'][0] - - -def test_hover(): - # 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) - - if LooseVersion(_utils.JEDI_VERSION) >= LooseVersion('0.15.0'): - contents = [{'language': 'python', 'value': 'main()'}, 'hello world'] - else: - contents = 'main()\n\nhello world' - - assert { - 'contents': contents - } == pyls_hover(doc, hov_position) - - assert {'contents': ''} == pyls_hover(doc, no_hov_position) diff --git a/external-deps/python-language-server/test/plugins/test_mccabe_lint.py b/external-deps/python-language-server/test/plugins/test_mccabe_lint.py deleted file mode 100644 index e5bc27f471d..00000000000 --- a/external-deps/python-language-server/test/plugins/test_mccabe_lint.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -from pyls import lsp, uris -from pyls.workspace import Document -from pyls.plugins import mccabe_lint - -DOC_URI = uris.from_fs_path(__file__) -DOC = """def hello(): -\tpass -""" - -DOC_SYNTAX_ERR = """def hello() -\tpass""" - - -def test_mccabe(config): - old_settings = config.settings - try: - config.update({'plugins': {'mccabe': {'threshold': 1}}}) - doc = Document(DOC_URI, DOC) - diags = mccabe_lint.pyls_lint(config, doc) - - assert all([d['source'] == 'mccabe' for d in diags]) - - # One we're expecting is: - msg = 'Cyclomatic complexity too high: 1 (threshold 1)' - mod_import = [d for d in diags if d['message'] == msg][0] - - assert mod_import['severity'] == lsp.DiagnosticSeverity.Warning - assert mod_import['range']['start'] == {'line': 0, 'character': 0} - assert mod_import['range']['end'] == {'line': 0, 'character': 6} - finally: - config._settings = old_settings - - -def test_mccabe_syntax_error(config): - doc = Document(DOC_URI, DOC_SYNTAX_ERR) - assert mccabe_lint.pyls_lint(config, doc) is None diff --git a/external-deps/python-language-server/test/plugins/test_pycodestyle_lint.py b/external-deps/python-language-server/test/plugins/test_pycodestyle_lint.py deleted file mode 100644 index eb1429b5fe4..00000000000 --- a/external-deps/python-language-server/test/plugins/test_pycodestyle_lint.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import os -from pyls import lsp, uris -from pyls.config.config import Config -from pyls.workspace import Document -from pyls.plugins import pycodestyle_lint - -DOC_URI = uris.from_fs_path(__file__) -DOC = """import sys - -def hello( ): -\tpass -print("hello" - ,"world" -) - -import json - - -""" - - -def test_pycodestyle(config): - doc = Document(DOC_URI, DOC) - diags = pycodestyle_lint.pyls_lint(config, doc) - - assert all([d['source'] == 'pycodestyle' for d in diags]) - - # One we're expecting is: - msg = 'W191 indentation contains tabs' - mod_import = [d for d in diags if d['message'] == msg][0] - - assert mod_import['code'] == 'W191' - assert mod_import['severity'] == lsp.DiagnosticSeverity.Warning - assert mod_import['range']['start'] == {'line': 3, 'character': 0} - assert mod_import['range']['end'] == {'line': 3, 'character': 6} - - msg = 'W391 blank line at end of file' - mod_import = [d for d in diags if d['message'] == msg][0] - - assert mod_import['code'] == 'W391' - assert mod_import['severity'] == lsp.DiagnosticSeverity.Warning - assert mod_import['range']['start'] == {'line': 10, 'character': 0} - assert mod_import['range']['end'] == {'line': 10, 'character': 1} - - msg = "E201 whitespace after '('" - mod_import = [d for d in diags if d['message'] == msg][0] - - assert mod_import['code'] == 'E201' - assert mod_import['severity'] == lsp.DiagnosticSeverity.Warning - assert mod_import['range']['start'] == {'line': 2, 'character': 10} - assert mod_import['range']['end'] == {'line': 2, 'character': 14} - - msg = "E128 continuation line under-indented for visual indent" - mod_import = [d for d in diags if d['message'] == msg][0] - - assert mod_import['code'] == 'E128' - assert mod_import['severity'] == lsp.DiagnosticSeverity.Warning - assert mod_import['range']['start'] == {'line': 5, 'character': 1} - assert mod_import['range']['end'] == {'line': 5, 'character': 10} - - -def test_pycodestyle_config(workspace): - """ Test that we load config files properly. - - Config files are loaded in the following order: - tox.ini pep8.cfg setup.cfg pycodestyle.cfg - - Each overriding the values in the last. - - These files are first looked for in the current document's - directory and then each parent directory until any one is found - terminating at the workspace root. - - If any section called 'pycodestyle' exists that will be solely used - and any config in a 'pep8' section will be ignored - """ - doc_uri = uris.from_fs_path(os.path.join(workspace.root_path, 'test.py')) - workspace.put_document(doc_uri, DOC) - doc = workspace.get_document(doc_uri) - config = Config(workspace.root_uri, {}, 1234, {}) - - # Make sure we get a warning for 'indentation contains tabs' - diags = pycodestyle_lint.pyls_lint(config, doc) - assert [d for d in diags if d['code'] == 'W191'] - - content = { - 'setup.cfg': ('[pycodestyle]\nignore = W191, E201, E128', True), - 'tox.ini': ('', False) - } - - for conf_file, (content, working) in list(content.items()): - # Now we'll add config file to ignore it - with open(os.path.join(workspace.root_path, conf_file), 'w+') as f: - f.write(content) - config.settings.cache_clear() - - # And make sure we don't get any warnings - diags = pycodestyle_lint.pyls_lint(config, doc) - assert len([d for d in diags if d['code'] == 'W191']) == (0 if working else 1) - assert len([d for d in diags if d['code'] == 'E201']) == (0 if working else 1) - assert [d for d in diags if d['code'] == 'W391'] - - os.unlink(os.path.join(workspace.root_path, conf_file)) - - # Make sure we can ignore via the PYLS config as well - config.update({'plugins': {'pycodestyle': {'ignore': ['W191', 'E201']}}}) - # And make sure we only get one warning - diags = pycodestyle_lint.pyls_lint(config, doc) - assert not [d for d in diags if d['code'] == 'W191'] - assert not [d for d in diags if d['code'] == 'E201'] - assert [d for d in diags if d['code'] == 'W391'] diff --git a/external-deps/python-language-server/test/plugins/test_pydocstyle_lint.py b/external-deps/python-language-server/test/plugins/test_pydocstyle_lint.py deleted file mode 100644 index f1c32703b8c..00000000000 --- a/external-deps/python-language-server/test/plugins/test_pydocstyle_lint.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import os -from pyls import lsp, uris -from pyls.workspace import Document -from pyls.plugins import pydocstyle_lint - -DOC_URI = uris.from_fs_path(os.path.join(os.path.dirname(__file__), "pydocstyle.py")) -TEST_DOC_URI = uris.from_fs_path(__file__) - -DOC = """import sys - -def hello(): -\tpass - -import json -""" - - -def test_pydocstyle(config): - doc = Document(DOC_URI, DOC) - diags = pydocstyle_lint.pyls_lint(config, doc) - - assert all([d['source'] == 'pydocstyle' for d in diags]) - - # One we're expecting is: - assert diags[0] == { - 'code': 'D100', - 'message': 'D100: Missing docstring in public module', - 'severity': lsp.DiagnosticSeverity.Warning, - 'range': { - 'start': {'line': 0, 'character': 0}, - 'end': {'line': 0, 'character': 11}, - }, - 'source': 'pydocstyle' - } - - -def test_pydocstyle_test_document(config): - # The default --match argument excludes test_* documents. - doc = Document(TEST_DOC_URI, "") - diags = pydocstyle_lint.pyls_lint(config, doc) - assert not diags - - -def test_pydocstyle_empty_source(config): - doc = Document(DOC_URI, "") - 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") - 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/external-deps/python-language-server/test/plugins/test_pyflakes_lint.py b/external-deps/python-language-server/test/plugins/test_pyflakes_lint.py deleted file mode 100644 index cf824c08a26..00000000000 --- a/external-deps/python-language-server/test/plugins/test_pyflakes_lint.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -from pyls import lsp, uris -from pyls.workspace import Document -from pyls.plugins import pyflakes_lint - -DOC_URI = uris.from_fs_path(__file__) -DOC = """import sys - -def hello(): -\tpass - -import json -""" - -DOC_SYNTAX_ERR = """def hello() - pass -""" - -DOC_UNDEFINED_NAME_ERR = "a = b" - - -DOC_ENCODING = u"""# encoding=utf-8 -import sys -""" - - -def test_pyflakes(): - doc = Document(DOC_URI, DOC) - diags = pyflakes_lint.pyls_lint(doc) - - # One we're expecting is: - msg = '\'sys\' imported but unused' - 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 - - -def test_syntax_error_pyflakes(): - doc = Document(DOC_URI, DOC_SYNTAX_ERR) - diag = pyflakes_lint.pyls_lint(doc)[0] - - assert diag['message'] == 'invalid syntax' - assert diag['range']['start'] == {'line': 0, 'character': 12} - assert diag['severity'] == lsp.DiagnosticSeverity.Error - - -def test_undefined_name_pyflakes(): - doc = Document(DOC_URI, DOC_UNDEFINED_NAME_ERR) - diag = pyflakes_lint.pyls_lint(doc)[0] - - assert diag['message'] == 'undefined name \'b\'' - assert diag['range']['start'] == {'line': 0, 'character': 4} - assert diag['severity'] == lsp.DiagnosticSeverity.Error - - -def test_unicode_encoding(): - doc = Document(DOC_URI, DOC_ENCODING) - diags = pyflakes_lint.pyls_lint(doc) - - assert len(diags) == 1 - assert diags[0]['message'] == '\'sys\' imported but unused' diff --git a/external-deps/python-language-server/test/plugins/test_pylint_lint.py b/external-deps/python-language-server/test/plugins/test_pylint_lint.py deleted file mode 100644 index b0d85fdc5ee..00000000000 --- a/external-deps/python-language-server/test/plugins/test_pylint_lint.py +++ /dev/null @@ -1,117 +0,0 @@ -# Copyright 2018 Google LLC. -import contextlib -import os -import tempfile - -from test import py2_only, py3_only -from pyls import lsp, uris -from pyls.workspace import Document -from pyls.plugins import pylint_lint - -DOC_URI = uris.from_fs_path(__file__) -DOC = """import sys - -def hello(): -\tpass - -import json -""" - -DOC_SYNTAX_ERR = """def hello() - pass -""" - - -@contextlib.contextmanager -def temp_document(doc_text): - try: - temp_file = tempfile.NamedTemporaryFile(mode='w', delete=False) - name = temp_file.name - temp_file.write(doc_text) - temp_file.close() - yield Document(uris.from_fs_path(name)) - finally: - os.remove(name) - - -def write_temp_doc(document, contents): - with open(document.path, 'w') as temp_file: - temp_file.write(contents) - - -def test_pylint(config): - with temp_document(DOC) as doc: - diags = pylint_lint.pyls_lint(config, doc, True) - - msg = '[unused-import] Unused import sys' - 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): - with temp_document(DOC_SYNTAX_ERR) as doc: - diag = pylint_lint.pyls_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': 12} - assert diag['severity'] == lsp.DiagnosticSeverity.Error - - -@py2_only -def test_syntax_error_pylint_py2(config): - with temp_document(DOC_SYNTAX_ERR) as doc: - diag = pylint_lint.pyls_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): - # 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) - - -def test_lint_caching(): - # Pylint can only operate on files, not in-memory contents. We cache the - # diagnostics after a run so we can continue displaying them until the file - # is saved again. - # - # We use PylintLinter.lint directly here rather than pyls_lint so we can - # pass --disable=invalid-name to pylint, since we want a temporary file but - # need to ensure that pylint doesn't give us invalid-name when our temp - # file has capital letters in its name. - - flags = '--disable=invalid-name' - with temp_document(DOC) as doc: - # Start with a file with errors. - diags = pylint_lint.PylintLinter.lint(doc, True, flags) - assert diags - - # Fix lint errors and write the changes to disk. Run the linter in the - # in-memory mode to check the cached diagnostic behavior. - write_temp_doc(doc, '') - assert pylint_lint.PylintLinter.lint(doc, False, flags) == diags - - # Now check the on-disk behavior. - assert not pylint_lint.PylintLinter.lint(doc, True, flags) - - # Make sure the cache was properly cleared. - assert not pylint_lint.PylintLinter.lint(doc, False, flags) - - -def test_per_file_caching(config): - # 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) diff --git a/external-deps/python-language-server/test/plugins/test_references.py b/external-deps/python-language-server/test/plugins/test_references.py deleted file mode 100644 index 7e7cbe75251..00000000000 --- a/external-deps/python-language-server/test/plugins/test_references.py +++ /dev/null @@ -1,79 +0,0 @@ -# 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 - - -DOC1_NAME = 'test1.py' -DOC2_NAME = 'test2.py' - -DOC1 = """class Test1(): - pass -""" - -DOC2 = """from test1 import Test1 - -try: - Test1() -except UnicodeError: - pass -""" - - -@pytest.fixture -def tmp_workspace(workspace): - def create_file(name, content): - fn = os.path.join(workspace.root_path, name) - with open(fn, 'w') as f: - f.write(content) - workspace.put_document(uris.from_fs_path(fn), content) - - create_file(DOC1_NAME, DOC1) - create_file(DOC2_NAME, DOC2) - - return workspace - - -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) - - refs = pyls_references(doc1, position) - - # Definition, the import and the instantiation - assert len(refs) == 3 - - # Briefly check excluding the definitions (also excludes imports, only counts uses) - no_def_refs = pyls_references(doc1, position, exclude_declaration=True) - assert len(no_def_refs) == 1 - - # Make sure our definition is correctly located - doc1_ref = [u for u in refs if u['uri'] == DOC1_URI][0] - assert doc1_ref['range']['start'] == {'line': 0, 'character': 6} - assert doc1_ref['range']['end'] == {'line': 0, 'character': 11} - - # Make sure our import is correctly located - doc2_import_ref = [u for u in refs if u['uri'] != DOC1_URI][0] - assert doc2_import_ref['range']['start'] == {'line': 0, 'character': 18} - assert doc2_import_ref['range']['end'] == {'line': 0, 'character': 23} - - doc2_usage_ref = [u for u in refs if u['uri'] != DOC1_URI][1] - assert doc2_usage_ref['range']['start'] == {'line': 3, 'character': 4} - assert doc2_usage_ref['range']['end'] == {'line': 3, 'character': 9} - - -def test_references_builtin(tmp_workspace): # pylint: disable=redefined-outer-name - # 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) - - 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} diff --git a/external-deps/python-language-server/test/plugins/test_signature.py b/external-deps/python-language-server/test/plugins/test_signature.py deleted file mode 100644 index 01a439a26c8..00000000000 --- a/external-deps/python-language-server/test/plugins/test_signature.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import pytest -from pyls import uris -from pyls.plugins import signature -from pyls.workspace import Document - -DOC_URI = uris.from_fs_path(__file__) -DOC = """import sys - -def main(param1, param2): - \"\"\" Main docstring - - Args: - param1 (str): Docs for param1 - \"\"\" - raise Exception() - -main( -""" - -MULTI_LINE_DOC = """import sys - -def main(param1=None, - param2=None, - param3=None, - param4=None, - param5=None, - param6=None, - param7=None, - param8=None): - \"\"\" Main docstring - - Args: - param1 (str): Docs for param1 - \"\"\" - raise Exception() - -main( -""" - - -def test_no_signature(): - # Over blank line - sig_position = {'line': 9, 'character': 0} - doc = Document(DOC_URI, DOC) - - sigs = signature.pyls_signature_help(doc, sig_position)['signatures'] - assert not sigs - - -def test_signature(): - # Over '( ' in main( - sig_position = {'line': 10, 'character': 5} - doc = Document(DOC_URI, DOC) - - sig_info = signature.pyls_signature_help(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 sig_info['activeParameter'] == 0 - - -def test_multi_line_signature(): - # Over '( ' in main( - sig_position = {'line': 17, 'character': 5} - doc = Document(DOC_URI, MULTI_LINE_DOC) - - sig_info = signature.pyls_signature_help(doc, sig_position) - - sigs = sig_info['signatures'] - assert len(sigs) == 1 - assert sigs[0]['label'] == ( - 'main(param1=None, param2=None, param3=None, param4=None, ' - '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 sig_info['activeParameter'] == 0 - - -@pytest.mark.parametrize('regex,doc', [ - (signature.SPHINX, " :param test: parameter docstring"), - (signature.EPYDOC, " @param test: parameter docstring"), - (signature.GOOGLE, " test (str): parameter docstring") -]) -def test_docstring_params(regex, doc): - m = regex.match(doc) - assert m.group('param') == "test" - assert m.group('doc') == "parameter docstring" diff --git a/external-deps/python-language-server/test/plugins/test_symbols.py b/external-deps/python-language-server/test/plugins/test_symbols.py deleted file mode 100644 index fa6f7df1bba..00000000000 --- a/external-deps/python-language-server/test/plugins/test_symbols.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import os -import sys - -from test.test_utils import MockWorkspace -import pytest - -from pyls import uris -from pyls.plugins.symbols import pyls_document_symbols -from pyls.lsp import SymbolKind -from pyls.workspace import Document - - -PY2 = sys.version[0] == '2' -LINUX = sys.platform.startswith('linux') -CI = os.environ.get('CI') -DOC_URI = uris.from_fs_path(__file__) -DOC = """import sys - -a = 'hello' - -class B: - def __init__(self): - x = 2 - self.y = x - -def main(x): - y = 2 * x - return y - -""" - - -def helper_check_symbols_all_scope(symbols): - # All eight symbols (import sys, a, B, __init__, x, y, main, y) - assert len(symbols) == 8 - - def sym(name): - return [s for s in symbols if s['name'] == name][0] - - # Check we have some sane mappings to VSCode constants - assert sym('a')['kind'] == SymbolKind.Variable - assert sym('B')['kind'] == SymbolKind.Class - assert sym('__init__')['kind'] == SymbolKind.Function - assert sym('main')['kind'] == SymbolKind.Function - - # Not going to get too in-depth here else we're just testing Jedi - assert sym('a')['location']['range']['start'] == {'line': 2, 'character': 0} - - -def test_symbols(config): - doc = Document(DOC_URI, DOC) - config.update({'plugins': {'jedi_symbols': {'all_scopes': False}}}) - symbols = pyls_document_symbols(config, doc) - - # All four symbols (import sys, a, B, main) - # y is not in the root scope, it shouldn't be returned - assert len(symbols) == 4 - - def sym(name): - return [s for s in symbols if s['name'] == name][0] - - # Check we have some sane mappings to VSCode constants - assert sym('a')['kind'] == SymbolKind.Variable - assert sym('B')['kind'] == SymbolKind.Class - assert sym('main')['kind'] == SymbolKind.Function - - # Not going to get too in-depth here else we're just testing Jedi - assert sym('a')['location']['range']['start'] == {'line': 2, 'character': 0} - - # Ensure that the symbol range spans the whole definition - assert sym('main')['location']['range']['start'] == {'line': 9, 'character': 0} - assert sym('main')['location']['range']['end'] == {'line': 12, 'character': 0} - - -def test_symbols_all_scopes(config): - doc = Document(DOC_URI, 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()) - - # Update config extra environment - env_path = '/tmp/pyenv/bin/python' - config.update({'plugins': {'jedi': {'environment': env_path}}}) - doc.update_config(config) - symbols = pyls_document_symbols(config, doc) - helper_check_symbols_all_scope(symbols) diff --git a/external-deps/python-language-server/test/plugins/test_yapf_format.py b/external-deps/python-language-server/test/plugins/test_yapf_format.py deleted file mode 100644 index 4bf6be32f8e..00000000000 --- a/external-deps/python-language-server/test/plugins/test_yapf_format.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -from pyls import uris -from pyls.plugins.yapf_format import pyls_format_document, pyls_format_range -from pyls.workspace import Document - -DOC_URI = uris.from_fs_path(__file__) -DOC = """A = [ - 'h', 'w', - - 'a' - ] - -B = ['h', - - -'w'] -""" - -GOOD_DOC = """A = ['hello', 'world']\n""" - - -def test_format(): - doc = Document(DOC_URI, 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_range = { - 'start': {'line': 0, 'character': 0}, - 'end': {'line': 4, 'character': 10} - } - res = pyls_format_range(doc, def_range) - - assert len(res) == 1 - - # Make sure B is still badly formatted - 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) - assert not pyls_format_document(doc) - - -def test_config_file(tmpdir): - # 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) - - # 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/external-deps/python-language-server/test/test_document.py b/external-deps/python-language-server/test/test_document.py deleted file mode 100644 index 4fd4ea2fa5c..00000000000 --- a/external-deps/python-language-server/test/test_document.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -from test.fixtures import DOC_URI, DOC -from pyls.workspace import Document - - -def test_document_props(doc): - assert doc.uri == DOC_URI - assert doc.source == DOC - - -def test_document_lines(doc): - assert len(doc.lines) == 4 - 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) - assert isinstance(document_mem.source, type(document_disk.source)) - - -def test_offset_at_position(doc): - assert doc.offset_at_position({'line': 0, 'character': 8}) == 8 - assert doc.offset_at_position({'line': 1, 'character': 5}) == 16 - assert doc.offset_at_position({'line': 2, 'character': 0}) == 12 - assert doc.offset_at_position({'line': 2, 'character': 4}) == 16 - assert doc.offset_at_position({'line': 4, 'character': 0}) == 51 - - -def test_word_at_position(doc): - """ Return the position under the cursor (or last in line if past the end) """ - # import sys - assert doc.word_at_position({'line': 0, 'character': 8}) == 'sys' - # Past end of import sys - assert doc.word_at_position({'line': 0, 'character': 1000}) == 'sys' - # Empty line - assert doc.word_at_position({'line': 1, 'character': 5}) == '' - # def main(): - assert doc.word_at_position({'line': 2, 'character': 0}) == 'def' - # Past end of file - assert doc.word_at_position({'line': 4, 'character': 0}) == '' - - -def test_document_empty_edit(): - doc = Document('file:///uri', u'') - doc.apply_change({ - 'range': { - 'start': {'line': 0, 'character': 0}, - 'end': {'line': 0, 'character': 0} - }, - 'text': u'f' - }) - assert doc.source == u'f' - - -def test_document_line_edit(): - doc = Document('file:///uri', u'itshelloworld') - doc.apply_change({ - 'text': u'goodbye', - 'range': { - 'start': {'line': 0, 'character': 3}, - 'end': {'line': 0, 'character': 8} - } - }) - assert doc.source == u'itsgoodbyeworld' - - -def test_document_multiline_edit(): - old = [ - "def hello(a, b):\n", - " print a\n", - " print b\n" - ] - doc = Document('file:///uri', u''.join(old)) - doc.apply_change({'text': u'print a, b', 'range': { - 'start': {'line': 1, 'character': 4}, - 'end': {'line': 2, 'character': 11} - }}) - assert doc.lines == [ - "def hello(a, b):\n", - " print a, b\n" - ] - - -def test_document_end_of_file_edit(): - old = [ - "print 'a'\n", - "print 'b'\n" - ] - doc = Document('file:///uri', u''.join(old)) - doc.apply_change({'text': u'o', 'range': { - 'start': {'line': 2, 'character': 0}, - 'end': {'line': 2, 'character': 0} - }}) - assert doc.lines == [ - "print 'a'\n", - "print 'b'\n", - "o", - ] diff --git a/external-deps/python-language-server/test/test_language_server.py b/external-deps/python-language-server/test/test_language_server.py deleted file mode 100644 index 14de6c81703..00000000000 --- a/external-deps/python-language-server/test/test_language_server.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import os -import time -import multiprocessing -from threading import Thread - -from test import unix_only -from pyls_jsonrpc.exceptions import JsonRpcMethodNotFound -import pytest - -from pyls.python_ls import start_io_lang_server, PythonLanguageServer - -CALL_TIMEOUT = 10 - - -def start_client(client): - client.start() - - -class _ClientServer(object): - """ A class to setup a client/server pair """ - def __init__(self, check_parent_process=False): - # Client to Server pipe - csr, csw = os.pipe() - # Server to client pipe - scr, scw = os.pipe() - - ParallelKind = multiprocessing.Process if os.name != 'nt' else Thread - - self.process = ParallelKind(target=start_io_lang_server, args=( - os.fdopen(csr, 'rb'), os.fdopen(scw, 'wb'), check_parent_process, PythonLanguageServer - )) - self.process.start() - - self.client = PythonLanguageServer(os.fdopen(scr, 'rb'), os.fdopen(csw, 'wb'), start_io_lang_server) - self.client_thread = Thread(target=start_client, args=[self.client]) - self.client_thread.daemon = True - self.client_thread.start() - - -@pytest.fixture -def client_server(): - """ A fixture that sets up a client/server pair and shuts down the server - This client/server pair does not support checking parent process aliveness - """ - client_server_pair = _ClientServer() - - yield client_server_pair.client - - shutdown_response = client_server_pair.client._endpoint.request('shutdown').result(timeout=CALL_TIMEOUT) - assert shutdown_response is None - client_server_pair.client._endpoint.notify('exit') - - -@pytest.fixture -def client_exited_server(): - """ A fixture that sets up a client/server pair that support checking parent process aliveness - and assert the server has already exited - """ - client_server_pair = _ClientServer(True) - - # yield client_server_pair.client - yield client_server_pair - - assert client_server_pair.process.is_alive() is False - - -def test_initialize(client_server): # pylint: disable=redefined-outer-name - response = client_server._endpoint.request('initialize', { - 'rootPath': os.path.dirname(__file__), - 'initializationOptions': {} - }).result(timeout=CALL_TIMEOUT) - assert 'capabilities' in response - - -@unix_only -def test_exit_with_parent_process_died(client_exited_server): # pylint: disable=redefined-outer-name - # language server should have already exited before responding - lsp_server, mock_process = client_exited_server.client, client_exited_server.process - # with pytest.raises(Exception): - lsp_server._endpoint.request('initialize', { - 'processId': mock_process.pid, - 'rootPath': os.path.dirname(__file__), - 'initializationOptions': {} - }).result(timeout=CALL_TIMEOUT) - - mock_process.terminate() - time.sleep(CALL_TIMEOUT) - assert not client_exited_server.client_thread.is_alive() - - -def test_not_exit_without_check_parent_process_flag(client_server): # pylint: disable=redefined-outer-name - response = client_server._endpoint.request('initialize', { - 'processId': 1234, - 'rootPath': os.path.dirname(__file__), - 'initializationOptions': {} - }).result(timeout=CALL_TIMEOUT) - assert 'capabilities' in response - - -def test_missing_message(client_server): # pylint: disable=redefined-outer-name - with pytest.raises(JsonRpcMethodNotFound): - client_server._endpoint.request('unknown_method').result(timeout=CALL_TIMEOUT) diff --git a/external-deps/python-language-server/test/test_uris.py b/external-deps/python-language-server/test/test_uris.py deleted file mode 100644 index d4e177e663f..00000000000 --- a/external-deps/python-language-server/test/test_uris.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -from test import unix_only, windows_only -import pytest -from pyls import uris - - -@unix_only -@pytest.mark.parametrize('uri,path', [ - ('file:///foo/bar#frag', '/foo/bar'), - ('file:/foo/bar#frag', '/foo/bar'), - ('file:/foo/space%20%3Fbar#frag', '/foo/space ?bar'), -]) -def test_to_fs_path(uri, path): - assert uris.to_fs_path(uri) == path - - -@windows_only -@pytest.mark.parametrize('uri,path', [ - ('file:///c:/far/boo', 'c:\\far\\boo'), - ('file:///C:/far/boo', 'c:\\far\\boo'), - ('file:///C:/far/space%20%3Fboo', 'c:\\far\\space ?boo'), -]) -def test_win_to_fs_path(uri, path): - assert uris.to_fs_path(uri) == path - - -@unix_only -@pytest.mark.parametrize('path,uri', [ - ('/foo/bar', 'file:///foo/bar'), - ('/foo/space ?bar', 'file:///foo/space%20%3Fbar'), -]) -def test_from_fs_path(path, uri): - assert uris.from_fs_path(path) == uri - - -@windows_only -@pytest.mark.parametrize('path,uri', [ - ('c:\\far\\boo', 'file:///c:/far/boo'), - ('C:\\far\\space ?boo', 'file:///c:/far/space%20%3Fboo') -]) -def test_win_from_fs_path(path, uri): - assert uris.from_fs_path(path) == uri - - -@pytest.mark.parametrize('uri,kwargs,new_uri', [ - ('file:///foo/bar', {'path': '/baz/boo'}, 'file:///baz/boo'), - ('file:///D:/hello%20world.py', {'path': 'D:/hello universe.py'}, 'file:///d:/hello%20universe.py') -]) -def test_uri_with(uri, kwargs, new_uri): - assert uris.uri_with(uri, **kwargs) == new_uri diff --git a/external-deps/python-language-server/test/test_utils.py b/external-deps/python-language-server/test/test_utils.py deleted file mode 100644 index d27f24ba6fe..00000000000 --- a/external-deps/python-language-server/test/test_utils.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import time -import sys - -import mock - -from pyls import _utils - - -class MockWorkspace(object): - """Mock workspace used by tests that use jedi environment.""" - - def __init__(self): - """Mock workspace used by tests that use jedi environment.""" - self._environments = {} - - # This is to avoid pyling tests of the variable not being used - sys.stdout.write(str(self._environments)) - - -def test_debounce(): - interval = 0.1 - obj = mock.Mock() - - @_utils.debounce(0.1) - def call_m(): - obj() - - assert not obj.mock_calls - - call_m() - call_m() - call_m() - assert not obj.mock_calls - - time.sleep(interval * 2) - assert len(obj.mock_calls) == 1 - - call_m() - time.sleep(interval * 2) - assert len(obj.mock_calls) == 2 - - -def test_debounce_keyed_by(): - interval = 0.1 - obj = mock.Mock() - - @_utils.debounce(0.1, keyed_by='key') - def call_m(key): - obj(key) - - assert not obj.mock_calls - - call_m(1) - call_m(2) - call_m(3) - assert not obj.mock_calls - - time.sleep(interval * 2) - obj.assert_has_calls([ - mock.call(1), - mock.call(2), - mock.call(3), - ], any_order=True) - assert len(obj.mock_calls) == 3 - - call_m(1) - call_m(1) - call_m(1) - time.sleep(interval * 2) - assert len(obj.mock_calls) == 4 - - -def test_list_to_string(): - assert _utils.list_to_string("string") == "string" - assert _utils.list_to_string(["a", "r", "r", "a", "y"]) == "a,r,r,a,y" - - -def test_find_parents(tmpdir): - subsubdir = tmpdir.ensure_dir("subdir", "subsubdir") - path = subsubdir.ensure("path.py") - test_cfg = tmpdir.ensure("test.cfg") - - assert _utils.find_parents(tmpdir.strpath, path.strpath, ["test.cfg"]) == [test_cfg.strpath] - - -def test_merge_dicts(): - assert _utils.merge_dicts( - {'a': True, 'b': {'x': 123, 'y': {'hello': 'world'}}}, - {'a': False, 'b': {'y': [], 'z': 987}} - ) == {'a': False, 'b': {'x': 123, 'y': [], 'z': 987}} - - -def test_clip_column(): - assert _utils.clip_column(0, [], 0) == 0 - assert _utils.clip_column(2, ['123'], 0) == 2 - assert _utils.clip_column(3, ['123'], 0) == 3 - assert _utils.clip_column(5, ['123'], 0) == 3 - assert _utils.clip_column(0, ['\n', '123'], 0) == 0 - assert _utils.clip_column(1, ['\n', '123'], 0) == 0 - assert _utils.clip_column(2, ['123\n', '123'], 0) == 2 - assert _utils.clip_column(3, ['123\n', '123'], 0) == 3 - assert _utils.clip_column(4, ['123\n', '123'], 1) == 3 diff --git a/external-deps/python-language-server/test/test_workspace.py b/external-deps/python-language-server/test/test_workspace.py deleted file mode 100644 index 9b5b7b06e48..00000000000 --- a/external-deps/python-language-server/test/test_workspace.py +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright 2017 Palantir Technologies, Inc. -import os -import sys - -import pytest - -from pyls import uris - -PY2 = sys.version_info.major == 2 - -if PY2: - import pathlib2 as pathlib -else: - import pathlib - - -DOC_URI = uris.from_fs_path(__file__) - - -def path_as_uri(path): - return pathlib.Path(os.path.abspath(path)).as_uri() - - -def test_local(pyls): - """ Since the workspace points to the test directory """ - assert pyls.workspace.is_local() - - -def test_put_document(pyls): - pyls.workspace.put_document(DOC_URI, 'content') - assert DOC_URI in pyls.workspace._docs - - -def test_get_document(pyls): - pyls.workspace.put_document(DOC_URI, 'TEXT') - assert pyls.workspace.get_document(DOC_URI).source == 'TEXT' - - -def test_get_missing_document(tmpdir, pyls): - source = 'TEXT' - doc_path = tmpdir.join("test_document.py") - doc_path.write(source) - doc_uri = uris.from_fs_path(str(doc_path)) - assert pyls.workspace.get_document(doc_uri).source == 'TEXT' - - -def test_rm_document(pyls): - pyls.workspace.put_document(DOC_URI, 'TEXT') - assert pyls.workspace.get_document(DOC_URI).source == 'TEXT' - pyls.workspace.rm_document(DOC_URI) - assert pyls.workspace.get_document(DOC_URI)._source is None - - -@pytest.mark.parametrize('metafiles', [('setup.py',), ('pyproject.toml',), ('setup.py', 'pyproject.toml')]) -def test_non_root_project(pyls, metafiles): - repo_root = os.path.join(pyls.workspace.root_path, 'repo-root') - os.mkdir(repo_root) - project_root = os.path.join(repo_root, 'project-root') - os.mkdir(project_root) - - for metafile in metafiles: - with open(os.path.join(project_root, metafile), 'w+') as f: - f.write('# ' + metafile) - - test_uri = uris.from_fs_path(os.path.join(project_root, 'hello/test.py')) - pyls.workspace.put_document(test_uri, 'assert True') - test_doc = pyls.workspace.get_document(test_uri) - assert project_root in test_doc.sys_path() - - -def test_root_project_with_no_setup_py(pyls): - """Default to workspace root.""" - workspace_root = pyls.workspace.root_path - test_uri = uris.from_fs_path(os.path.join(workspace_root, 'hello/test.py')) - pyls.workspace.put_document(test_uri, 'assert True') - test_doc = pyls.workspace.get_document(test_uri) - assert workspace_root in test_doc.sys_path() - - -def test_multiple_workspaces(tmpdir, pyls): - workspace1_dir = tmpdir.mkdir('workspace1') - workspace2_dir = tmpdir.mkdir('workspace2') - file1 = workspace1_dir.join('file1.py') - file2 = workspace2_dir.join('file1.py') - file1.write('import os') - file2.write('import sys') - - msg = { - 'uri': path_as_uri(str(file1)), - 'version': 1, - 'text': 'import os' - } - - pyls.m_text_document__did_open(textDocument=msg) - assert msg['uri'] in pyls.workspace._docs - - added_workspaces = [{'uri': path_as_uri(str(x))} - for x in (workspace1_dir, workspace2_dir)] - pyls.m_workspace__did_change_workspace_folders( - added=added_workspaces, removed=[]) - - for workspace in added_workspaces: - assert workspace['uri'] in pyls.workspaces - - workspace1_uri = added_workspaces[0]['uri'] - assert msg['uri'] not in pyls.workspace._docs - assert msg['uri'] in pyls.workspaces[workspace1_uri]._docs - - msg = { - 'uri': path_as_uri(str(file2)), - 'version': 1, - 'text': 'import sys' - } - pyls.m_text_document__did_open(textDocument=msg) - - workspace2_uri = added_workspaces[1]['uri'] - assert msg['uri'] in pyls.workspaces[workspace2_uri]._docs - - pyls.m_workspace__did_change_workspace_folders( - added=[], removed=[added_workspaces[0]]) - assert workspace1_uri not in pyls.workspaces diff --git a/external-deps/python-language-server/versioneer.py b/external-deps/python-language-server/versioneer.py deleted file mode 100644 index 64fea1c8927..00000000000 --- a/external-deps/python-language-server/versioneer.py +++ /dev/null @@ -1,1822 +0,0 @@ - -# Version: 0.18 - -"""The Versioneer - like a rocketeer, but for versions. - -The Versioneer -============== - -* like a rocketeer, but for versions! -* https://github.com/warner/python-versioneer -* Brian Warner -* License: Public Domain -* Compatible With: python2.6, 2.7, 3.2, 3.3, 3.4, 3.5, 3.6, and pypy -* [![Latest Version] -(https://pypip.in/version/versioneer/badge.svg?style=flat) -](https://pypi.python.org/pypi/versioneer/) -* [![Build Status] -(https://travis-ci.org/warner/python-versioneer.png?branch=master) -](https://travis-ci.org/warner/python-versioneer) - -This is a tool for managing a recorded version number in distutils-based -python projects. The goal is to remove the tedious and error-prone "update -the embedded version string" step from your release process. Making a new -release should be as easy as recording a new tag in your version-control -system, and maybe making new tarballs. - - -## Quick Install - -* `pip install versioneer` to somewhere to your $PATH -* add a `[versioneer]` section to your setup.cfg (see below) -* run `versioneer install` in your source tree, commit the results - -## Version Identifiers - -Source trees come from a variety of places: - -* a version-control system checkout (mostly used by developers) -* a nightly tarball, produced by build automation -* a snapshot tarball, produced by a web-based VCS browser, like github's - "tarball from tag" feature -* a release tarball, produced by "setup.py sdist", distributed through PyPI - -Within each source tree, the version identifier (either a string or a number, -this tool is format-agnostic) can come from a variety of places: - -* ask the VCS tool itself, e.g. "git describe" (for checkouts), which knows - about recent "tags" and an absolute revision-id -* the name of the directory into which the tarball was unpacked -* an expanded VCS keyword ($Id$, etc) -* a `_version.py` created by some earlier build step - -For released software, the version identifier is closely related to a VCS -tag. Some projects use tag names that include more than just the version -string (e.g. "myproject-1.2" instead of just "1.2"), in which case the tool -needs to strip the tag prefix to extract the version identifier. For -unreleased software (between tags), the version identifier should provide -enough information to help developers recreate the same tree, while also -giving them an idea of roughly how old the tree is (after version 1.2, before -version 1.3). Many VCS systems can report a description that captures this, -for example `git describe --tags --dirty --always` reports things like -"0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the -0.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has -uncommitted changes. - -The version identifier is used for multiple purposes: - -* to allow the module to self-identify its version: `myproject.__version__` -* to choose a name and prefix for a 'setup.py sdist' tarball - -## Theory of Operation - -Versioneer works by adding a special `_version.py` file into your source -tree, where your `__init__.py` can import it. This `_version.py` knows how to -dynamically ask the VCS tool for version information at import time. - -`_version.py` also contains `$Revision$` markers, and the installation -process marks `_version.py` to have this marker rewritten with a tag name -during the `git archive` command. As a result, generated tarballs will -contain enough information to get the proper version. - -To allow `setup.py` to compute a version too, a `versioneer.py` is added to -the top level of your source tree, next to `setup.py` and the `setup.cfg` -that configures it. This overrides several distutils/setuptools commands to -compute the version when invoked, and changes `setup.py build` and `setup.py -sdist` to replace `_version.py` with a small static file that contains just -the generated version data. - -## Installation - -See [INSTALL.md](./INSTALL.md) for detailed installation instructions. - -## Version-String Flavors - -Code which uses Versioneer can learn about its version string at runtime by -importing `_version` from your main `__init__.py` file and running the -`get_versions()` function. From the "outside" (e.g. in `setup.py`), you can -import the top-level `versioneer.py` and run `get_versions()`. - -Both functions return a dictionary with different flavors of version -information: - -* `['version']`: A condensed version string, rendered using the selected - style. This is the most commonly used value for the project's version - string. The default "pep440" style yields strings like `0.11`, - `0.11+2.g1076c97`, or `0.11+2.g1076c97.dirty`. See the "Styles" section - below for alternative styles. - -* `['full-revisionid']`: detailed revision identifier. For Git, this is the - full SHA1 commit id, e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac". - -* `['date']`: Date and time of the latest `HEAD` commit. For Git, it is the - commit date in ISO 8601 format. This will be None if the date is not - available. - -* `['dirty']`: a boolean, True if the tree has uncommitted changes. Note that - this is only accurate if run in a VCS checkout, otherwise it is likely to - be False or None - -* `['error']`: if the version string could not be computed, this will be set - to a string describing the problem, otherwise it will be None. It may be - useful to throw an exception in setup.py if this is set, to avoid e.g. - creating tarballs with a version string of "unknown". - -Some variants are more useful than others. Including `full-revisionid` in a -bug report should allow developers to reconstruct the exact code being tested -(or indicate the presence of local changes that should be shared with the -developers). `version` is suitable for display in an "about" box or a CLI -`--version` output: it can be easily compared against release notes and lists -of bugs fixed in various releases. - -The installer adds the following text to your `__init__.py` to place a basic -version in `YOURPROJECT.__version__`: - - from ._version import get_versions - __version__ = get_versions()['version'] - del get_versions - -## Styles - -The setup.cfg `style=` configuration controls how the VCS information is -rendered into a version string. - -The default style, "pep440", produces a PEP440-compliant string, equal to the -un-prefixed tag name for actual releases, and containing an additional "local -version" section with more detail for in-between builds. For Git, this is -TAG[+DISTANCE.gHEX[.dirty]] , using information from `git describe --tags ---dirty --always`. For example "0.11+2.g1076c97.dirty" indicates that the -tree is like the "1076c97" commit but has uncommitted changes (".dirty"), and -that this commit is two revisions ("+2") beyond the "0.11" tag. For released -software (exactly equal to a known tag), the identifier will only contain the -stripped tag, e.g. "0.11". - -Other styles are available. See [details.md](details.md) in the Versioneer -source tree for descriptions. - -## Debugging - -Versioneer tries to avoid fatal errors: if something goes wrong, it will tend -to return a version of "0+unknown". To investigate the problem, run `setup.py -version`, which will run the version-lookup code in a verbose mode, and will -display the full contents of `get_versions()` (including the `error` string, -which may help identify what went wrong). - -## Known Limitations - -Some situations are known to cause problems for Versioneer. This details the -most significant ones. More can be found on Github -[issues page](https://github.com/warner/python-versioneer/issues). - -### Subprojects - -Versioneer has limited support for source trees in which `setup.py` is not in -the root directory (e.g. `setup.py` and `.git/` are *not* siblings). The are -two common reasons why `setup.py` might not be in the root: - -* Source trees which contain multiple subprojects, such as - [Buildbot](https://github.com/buildbot/buildbot), which contains both - "master" and "slave" subprojects, each with their own `setup.py`, - `setup.cfg`, and `tox.ini`. Projects like these produce multiple PyPI - distributions (and upload multiple independently-installable tarballs). -* Source trees whose main purpose is to contain a C library, but which also - provide bindings to Python (and perhaps other langauges) in subdirectories. - -Versioneer will look for `.git` in parent directories, and most operations -should get the right version string. However `pip` and `setuptools` have bugs -and implementation details which frequently cause `pip install .` from a -subproject directory to fail to find a correct version string (so it usually -defaults to `0+unknown`). - -`pip install --editable .` should work correctly. `setup.py install` might -work too. - -Pip-8.1.1 is known to have this problem, but hopefully it will get fixed in -some later version. - -[Bug #38](https://github.com/warner/python-versioneer/issues/38) is tracking -this issue. The discussion in -[PR #61](https://github.com/warner/python-versioneer/pull/61) describes the -issue from the Versioneer side in more detail. -[pip PR#3176](https://github.com/pypa/pip/pull/3176) and -[pip PR#3615](https://github.com/pypa/pip/pull/3615) contain work to improve -pip to let Versioneer work correctly. - -Versioneer-0.16 and earlier only looked for a `.git` directory next to the -`setup.cfg`, so subprojects were completely unsupported with those releases. - -### Editable installs with setuptools <= 18.5 - -`setup.py develop` and `pip install --editable .` allow you to install a -project into a virtualenv once, then continue editing the source code (and -test) without re-installing after every change. - -"Entry-point scripts" (`setup(entry_points={"console_scripts": ..})`) are a -convenient way to specify executable scripts that should be installed along -with the python package. - -These both work as expected when using modern setuptools. When using -setuptools-18.5 or earlier, however, certain operations will cause -`pkg_resources.DistributionNotFound` errors when running the entrypoint -script, which must be resolved by re-installing the package. This happens -when the install happens with one version, then the egg_info data is -regenerated while a different version is checked out. Many setup.py commands -cause egg_info to be rebuilt (including `sdist`, `wheel`, and installing into -a different virtualenv), so this can be surprising. - -[Bug #83](https://github.com/warner/python-versioneer/issues/83) describes -this one, but upgrading to a newer version of setuptools should probably -resolve it. - -### Unicode version strings - -While Versioneer works (and is continually tested) with both Python 2 and -Python 3, it is not entirely consistent with bytes-vs-unicode distinctions. -Newer releases probably generate unicode version strings on py2. It's not -clear that this is wrong, but it may be surprising for applications when then -write these strings to a network connection or include them in bytes-oriented -APIs like cryptographic checksums. - -[Bug #71](https://github.com/warner/python-versioneer/issues/71) investigates -this question. - - -## Updating Versioneer - -To upgrade your project to a new release of Versioneer, do the following: - -* install the new Versioneer (`pip install -U versioneer` or equivalent) -* edit `setup.cfg`, if necessary, to include any new configuration settings - indicated by the release notes. See [UPGRADING](./UPGRADING.md) for details. -* re-run `versioneer install` in your source tree, to replace - `SRC/_version.py` -* commit any changed files - -## Future Directions - -This tool is designed to make it easily extended to other version-control -systems: all VCS-specific components are in separate directories like -src/git/ . The top-level `versioneer.py` script is assembled from these -components by running make-versioneer.py . In the future, make-versioneer.py -will take a VCS name as an argument, and will construct a version of -`versioneer.py` that is specific to the given VCS. It might also take the -configuration arguments that are currently provided manually during -installation by editing setup.py . Alternatively, it might go the other -direction and include code from all supported VCS systems, reducing the -number of intermediate scripts. - - -## License - -To make Versioneer easier to embed, all its code is dedicated to the public -domain. The `_version.py` that it creates is also in the public domain. -Specifically, both are released under the Creative Commons "Public Domain -Dedication" license (CC0-1.0), as described in -https://creativecommons.org/publicdomain/zero/1.0/ . - -""" - -from __future__ import print_function -try: - import configparser -except ImportError: - import ConfigParser as configparser -import errno -import json -import os -import re -import subprocess -import sys - - -class VersioneerConfig: - """Container for Versioneer configuration parameters.""" - - -def get_root(): - """Get the project root directory. - - We require that all commands are run from the project root, i.e. the - directory that contains setup.py, setup.cfg, and versioneer.py . - """ - root = os.path.realpath(os.path.abspath(os.getcwd())) - setup_py = os.path.join(root, "setup.py") - versioneer_py = os.path.join(root, "versioneer.py") - if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): - # allow 'python path/to/setup.py COMMAND' - root = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0]))) - setup_py = os.path.join(root, "setup.py") - versioneer_py = os.path.join(root, "versioneer.py") - if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): - err = ("Versioneer was unable to run the project root directory. " - "Versioneer requires setup.py to be executed from " - "its immediate directory (like 'python setup.py COMMAND'), " - "or in a way that lets it use sys.argv[0] to find the root " - "(like 'python path/to/setup.py COMMAND').") - raise VersioneerBadRootError(err) - try: - # Certain runtime workflows (setup.py install/develop in a setuptools - # tree) execute all dependencies in a single python process, so - # "versioneer" may be imported multiple times, and python's shared - # module-import table will cache the first one. So we can't use - # os.path.dirname(__file__), as that will find whichever - # versioneer.py was first imported, even in later projects. - me = os.path.realpath(os.path.abspath(__file__)) - me_dir = os.path.normcase(os.path.splitext(me)[0]) - vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) - if me_dir != vsr_dir: - print("Warning: build in %s is using versioneer.py from %s" - % (os.path.dirname(me), versioneer_py)) - except NameError: - pass - return root - - -def get_config_from_root(root): - """Read the project setup.cfg file to determine Versioneer config.""" - # This might raise EnvironmentError (if setup.cfg is missing), or - # configparser.NoSectionError (if it lacks a [versioneer] section), or - # configparser.NoOptionError (if it lacks "VCS="). See the docstring at - # the top of versioneer.py for instructions on writing your setup.cfg . - setup_cfg = os.path.join(root, "setup.cfg") - parser = configparser.SafeConfigParser() - with open(setup_cfg, "r") as f: - parser.readfp(f) - VCS = parser.get("versioneer", "VCS") # mandatory - - def get(parser, name): - if parser.has_option("versioneer", name): - return parser.get("versioneer", name) - return None - cfg = VersioneerConfig() - cfg.VCS = VCS - cfg.style = get(parser, "style") or "" - cfg.versionfile_source = get(parser, "versionfile_source") - cfg.versionfile_build = get(parser, "versionfile_build") - cfg.tag_prefix = get(parser, "tag_prefix") - if cfg.tag_prefix in ("''", '""'): - cfg.tag_prefix = "" - cfg.parentdir_prefix = get(parser, "parentdir_prefix") - cfg.verbose = get(parser, "verbose") - return cfg - - -class NotThisMethod(Exception): - """Exception raised if a method is not valid for the current scenario.""" - - -# these dictionaries contain VCS-specific tools -LONG_VERSION_PY = {} -HANDLERS = {} - - -def register_vcs_handler(vcs, method): # decorator - """Decorator to mark a method as the handler for a particular VCS.""" - def decorate(f): - """Store f in HANDLERS[vcs][method].""" - if vcs not in HANDLERS: - HANDLERS[vcs] = {} - HANDLERS[vcs][method] = f - return f - return decorate - - -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): - """Call the given command(s).""" - assert isinstance(commands, list) - p = None - for c in commands: - try: - dispcmd = str([c] + args) - # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) - break - except EnvironmentError: - e = sys.exc_info()[1] - if e.errno == errno.ENOENT: - continue - if verbose: - print("unable to run %s" % dispcmd) - print(e) - return None, None - else: - if verbose: - print("unable to find command, tried %s" % (commands,)) - return None, None - stdout = p.communicate()[0].strip() - if sys.version_info[0] >= 3: - stdout = stdout.decode() - if p.returncode != 0: - if verbose: - print("unable to run %s (error)" % dispcmd) - print("stdout was %s" % stdout) - return None, p.returncode - return stdout, p.returncode - - -LONG_VERSION_PY['git'] = ''' -# This file helps to compute a version number in source trees obtained from -# git-archive tarball (such as those provided by githubs download-from-tag -# feature). Distribution tarballs (built by setup.py sdist) and build -# directories (produced by setup.py build) will contain a much shorter file -# that just contains the computed version number. - -# This file is released into the public domain. Generated by -# versioneer-0.18 (https://github.com/warner/python-versioneer) - -"""Git implementation of _version.py.""" - -import errno -import os -import re -import subprocess -import sys - - -def get_keywords(): - """Get the keywords needed to look up the version information.""" - # these strings will be replaced by git during git-archive. - # setup.py/versioneer.py will grep for the variable names, so they must - # each be defined on a line of their own. _version.py will just call - # get_keywords(). - git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s" - git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s" - git_date = "%(DOLLAR)sFormat:%%ci%(DOLLAR)s" - keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} - return keywords - - -class VersioneerConfig: - """Container for Versioneer configuration parameters.""" - - -def get_config(): - """Create, populate and return the VersioneerConfig() object.""" - # these strings are filled in when 'setup.py versioneer' creates - # _version.py - cfg = VersioneerConfig() - cfg.VCS = "git" - cfg.style = "%(STYLE)s" - cfg.tag_prefix = "%(TAG_PREFIX)s" - cfg.parentdir_prefix = "%(PARENTDIR_PREFIX)s" - cfg.versionfile_source = "%(VERSIONFILE_SOURCE)s" - cfg.verbose = False - return cfg - - -class NotThisMethod(Exception): - """Exception raised if a method is not valid for the current scenario.""" - - -LONG_VERSION_PY = {} -HANDLERS = {} - - -def register_vcs_handler(vcs, method): # decorator - """Decorator to mark a method as the handler for a particular VCS.""" - def decorate(f): - """Store f in HANDLERS[vcs][method].""" - if vcs not in HANDLERS: - HANDLERS[vcs] = {} - HANDLERS[vcs][method] = f - return f - return decorate - - -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): - """Call the given command(s).""" - assert isinstance(commands, list) - p = None - for c in commands: - try: - dispcmd = str([c] + args) - # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) - break - except EnvironmentError: - e = sys.exc_info()[1] - if e.errno == errno.ENOENT: - continue - if verbose: - print("unable to run %%s" %% dispcmd) - print(e) - return None, None - else: - if verbose: - print("unable to find command, tried %%s" %% (commands,)) - return None, None - stdout = p.communicate()[0].strip() - if sys.version_info[0] >= 3: - stdout = stdout.decode() - if p.returncode != 0: - if verbose: - print("unable to run %%s (error)" %% dispcmd) - print("stdout was %%s" %% stdout) - return None, p.returncode - return stdout, p.returncode - - -def versions_from_parentdir(parentdir_prefix, root, verbose): - """Try to determine the version from the parent directory name. - - Source tarballs conventionally unpack into a directory that includes both - the project name and a version string. We will also support searching up - two directory levels for an appropriately named parent directory - """ - rootdirs = [] - - for i in range(3): - dirname = os.path.basename(root) - if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} - else: - rootdirs.append(root) - root = os.path.dirname(root) # up a level - - if verbose: - print("Tried directories %%s but none started with prefix %%s" %% - (str(rootdirs), parentdir_prefix)) - raise NotThisMethod("rootdir doesn't start with parentdir_prefix") - - -@register_vcs_handler("git", "get_keywords") -def git_get_keywords(versionfile_abs): - """Extract version information from the given file.""" - # the code embedded in _version.py can just fetch the value of these - # keywords. When used from setup.py, we don't want to import _version.py, - # so we do it with a regexp instead. This function is not used from - # _version.py. - keywords = {} - try: - f = open(versionfile_abs, "r") - for line in f.readlines(): - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["full"] = mo.group(1) - if line.strip().startswith("git_date ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["date"] = mo.group(1) - f.close() - except EnvironmentError: - pass - return keywords - - -@register_vcs_handler("git", "keywords") -def git_versions_from_keywords(keywords, tag_prefix, verbose): - """Get version information from git keywords.""" - if not keywords: - raise NotThisMethod("no keywords at all, weird") - date = keywords.get("date") - if date is not None: - # git-2.2.0 added "%%cI", which expands to an ISO-8601 -compliant - # datestamp. However we prefer "%%ci" (which expands to an "ISO-8601 - # -like" string, which we must then edit to make compliant), because - # it's been around since git-1.5.3, and it's too difficult to - # discover which version we're using, or to work around using an - # older one. - date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - refnames = keywords["refnames"].strip() - if refnames.startswith("$Format"): - if verbose: - print("keywords are unexpanded, not using") - raise NotThisMethod("unexpanded keywords, not a git-archive tarball") - refs = set([r.strip() for r in refnames.strip("()").split(",")]) - # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of - # just "foo-1.0". If we see a "tag: " prefix, prefer those. - TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %%d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) - if verbose: - print("discarding '%%s', no digits" %% ",".join(refs - tags)) - if verbose: - print("likely tags: %%s" %% ",".join(sorted(tags))) - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] - if verbose: - print("picking %%s" %% r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} - # no suitable tags, so version is "0+unknown", but full hex is still there - if verbose: - print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} - - -@register_vcs_handler("git", "pieces_from_vcs") -def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): - """Get version from 'git describe' in the root of the source tree. - - This only gets called if the git-archive 'subst' keywords were *not* - expanded, and _version.py hasn't already been rewritten with a short - version string, meaning we're inside a checked out source tree. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) - if rc != 0: - if verbose: - print("Directory %%s not under git control" %% root) - raise NotThisMethod("'git rev-parse --git-dir' returned error") - - # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] - # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%%s*" %% tag_prefix], - cwd=root) - # --long was added in git-1.5.5 - if describe_out is None: - raise NotThisMethod("'git describe' failed") - describe_out = describe_out.strip() - full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) - if full_out is None: - raise NotThisMethod("'git rev-parse' failed") - full_out = full_out.strip() - - pieces = {} - pieces["long"] = full_out - pieces["short"] = full_out[:7] # maybe improved later - pieces["error"] = None - - # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] - # TAG might have hyphens. - git_describe = describe_out - - # look for -dirty suffix - dirty = git_describe.endswith("-dirty") - pieces["dirty"] = dirty - if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] - - # now we have TAG-NUM-gHEX or HEX - - if "-" in git_describe: - # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) - if not mo: - # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%%s'" - %% describe_out) - return pieces - - # tag - full_tag = mo.group(1) - if not full_tag.startswith(tag_prefix): - if verbose: - fmt = "tag '%%s' doesn't start with prefix '%%s'" - print(fmt %% (full_tag, tag_prefix)) - pieces["error"] = ("tag '%%s' doesn't start with prefix '%%s'" - %% (full_tag, tag_prefix)) - return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] - - # distance: number of commits since tag - pieces["distance"] = int(mo.group(2)) - - # commit: short hex revision ID - pieces["short"] = mo.group(3) - - else: - # HEX: no tags - pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) - pieces["distance"] = int(count_out) # total number of commits - - # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%%ci", "HEAD"], - cwd=root)[0].strip() - pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - - return pieces - - -def plus_or_dot(pieces): - """Return a + if we don't already have one, else return a .""" - if "+" in pieces.get("closest-tag", ""): - return "." - return "+" - - -def render_pep440(pieces): - """Build up version string, with post-release "local version identifier". - - Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you - get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty - - Exceptions: - 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += plus_or_dot(pieces) - rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0+untagged.%%d.g%%s" %% (pieces["distance"], - pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_pre(pieces): - """TAG[.post.devDISTANCE] -- No -dirty. - - Exceptions: - 1: no tags. 0.post.devDISTANCE - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += ".post.dev%%d" %% pieces["distance"] - else: - # exception #1 - rendered = "0.post.dev%%d" %% pieces["distance"] - return rendered - - -def render_pep440_post(pieces): - """TAG[.postDISTANCE[.dev0]+gHEX] . - - The ".dev0" means dirty. Note that .dev0 sorts backwards - (a dirty tree will appear "older" than the corresponding clean one), - but you shouldn't be releasing software with -dirty anyways. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%%s" %% pieces["short"] - else: - # exception #1 - rendered = "0.post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += "+g%%s" %% pieces["short"] - return rendered - - -def render_pep440_old(pieces): - """TAG[.postDISTANCE[.dev0]] . - - The ".dev0" means dirty. - - Eexceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - else: - # exception #1 - rendered = "0.post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - return rendered - - -def render_git_describe(pieces): - """TAG[-DISTANCE-gHEX][-dirty]. - - Like 'git describe --tags --dirty --always'. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render_git_describe_long(pieces): - """TAG-DISTANCE-gHEX[-dirty]. - - Like 'git describe --tags --dirty --always -long'. - The distance/hash is unconditional. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render(pieces, style): - """Render the given version pieces into the requested style.""" - if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} - - if not style or style == "default": - style = "pep440" # the default - - if style == "pep440": - rendered = render_pep440(pieces) - elif style == "pep440-pre": - rendered = render_pep440_pre(pieces) - elif style == "pep440-post": - rendered = render_pep440_post(pieces) - elif style == "pep440-old": - rendered = render_pep440_old(pieces) - elif style == "git-describe": - rendered = render_git_describe(pieces) - elif style == "git-describe-long": - rendered = render_git_describe_long(pieces) - else: - raise ValueError("unknown style '%%s'" %% style) - - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} - - -def get_versions(): - """Get version information or return default if unable to do so.""" - # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have - # __file__, we can work backwards from there to the root. Some - # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which - # case we can only use expanded keywords. - - cfg = get_config() - verbose = cfg.verbose - - try: - return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, - verbose) - except NotThisMethod: - pass - - try: - root = os.path.realpath(__file__) - # versionfile_source is the relative path from the top of the source - # tree (where the .git directory might live) to this file. Invert - # this to find the root from __file__. - for i in cfg.versionfile_source.split('/'): - root = os.path.dirname(root) - except NameError: - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None} - - try: - pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) - return render(pieces, cfg.style) - except NotThisMethod: - pass - - try: - if cfg.parentdir_prefix: - return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) - except NotThisMethod: - pass - - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", "date": None} -''' - - -@register_vcs_handler("git", "get_keywords") -def git_get_keywords(versionfile_abs): - """Extract version information from the given file.""" - # the code embedded in _version.py can just fetch the value of these - # keywords. When used from setup.py, we don't want to import _version.py, - # so we do it with a regexp instead. This function is not used from - # _version.py. - keywords = {} - try: - f = open(versionfile_abs, "r") - for line in f.readlines(): - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["full"] = mo.group(1) - if line.strip().startswith("git_date ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["date"] = mo.group(1) - f.close() - except EnvironmentError: - pass - return keywords - - -@register_vcs_handler("git", "keywords") -def git_versions_from_keywords(keywords, tag_prefix, verbose): - """Get version information from git keywords.""" - if not keywords: - raise NotThisMethod("no keywords at all, weird") - date = keywords.get("date") - if date is not None: - # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant - # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 - # -like" string, which we must then edit to make compliant), because - # it's been around since git-1.5.3, and it's too difficult to - # discover which version we're using, or to work around using an - # older one. - date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - refnames = keywords["refnames"].strip() - if refnames.startswith("$Format"): - if verbose: - print("keywords are unexpanded, not using") - raise NotThisMethod("unexpanded keywords, not a git-archive tarball") - refs = set([r.strip() for r in refnames.strip("()").split(",")]) - # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of - # just "foo-1.0". If we see a "tag: " prefix, prefer those. - TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) - if verbose: - print("discarding '%s', no digits" % ",".join(refs - tags)) - if verbose: - print("likely tags: %s" % ",".join(sorted(tags))) - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] - if verbose: - print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} - # no suitable tags, so version is "0+unknown", but full hex is still there - if verbose: - print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} - - -@register_vcs_handler("git", "pieces_from_vcs") -def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): - """Get version from 'git describe' in the root of the source tree. - - This only gets called if the git-archive 'subst' keywords were *not* - expanded, and _version.py hasn't already been rewritten with a short - version string, meaning we're inside a checked out source tree. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) - if rc != 0: - if verbose: - print("Directory %s not under git control" % root) - raise NotThisMethod("'git rev-parse --git-dir' returned error") - - # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] - # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%s*" % tag_prefix], - cwd=root) - # --long was added in git-1.5.5 - if describe_out is None: - raise NotThisMethod("'git describe' failed") - describe_out = describe_out.strip() - full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) - if full_out is None: - raise NotThisMethod("'git rev-parse' failed") - full_out = full_out.strip() - - pieces = {} - pieces["long"] = full_out - pieces["short"] = full_out[:7] # maybe improved later - pieces["error"] = None - - # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] - # TAG might have hyphens. - git_describe = describe_out - - # look for -dirty suffix - dirty = git_describe.endswith("-dirty") - pieces["dirty"] = dirty - if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] - - # now we have TAG-NUM-gHEX or HEX - - if "-" in git_describe: - # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) - if not mo: - # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) - return pieces - - # tag - full_tag = mo.group(1) - if not full_tag.startswith(tag_prefix): - if verbose: - fmt = "tag '%s' doesn't start with prefix '%s'" - print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) - return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] - - # distance: number of commits since tag - pieces["distance"] = int(mo.group(2)) - - # commit: short hex revision ID - pieces["short"] = mo.group(3) - - else: - # HEX: no tags - pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) - pieces["distance"] = int(count_out) # total number of commits - - # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], - cwd=root)[0].strip() - pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - - return pieces - - -def do_vcs_install(manifest_in, versionfile_source, ipy): - """Git-specific installation logic for Versioneer. - - For Git, this means creating/changing .gitattributes to mark _version.py - for export-subst keyword substitution. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - files = [manifest_in, versionfile_source] - if ipy: - files.append(ipy) - try: - me = __file__ - if me.endswith(".pyc") or me.endswith(".pyo"): - me = os.path.splitext(me)[0] + ".py" - versioneer_file = os.path.relpath(me) - except NameError: - versioneer_file = "versioneer.py" - files.append(versioneer_file) - present = False - try: - f = open(".gitattributes", "r") - for line in f.readlines(): - if line.strip().startswith(versionfile_source): - if "export-subst" in line.strip().split()[1:]: - present = True - f.close() - except EnvironmentError: - pass - if not present: - f = open(".gitattributes", "a+") - f.write("%s export-subst\n" % versionfile_source) - f.close() - files.append(".gitattributes") - run_command(GITS, ["add", "--"] + files) - - -def versions_from_parentdir(parentdir_prefix, root, verbose): - """Try to determine the version from the parent directory name. - - Source tarballs conventionally unpack into a directory that includes both - the project name and a version string. We will also support searching up - two directory levels for an appropriately named parent directory - """ - rootdirs = [] - - for i in range(3): - dirname = os.path.basename(root) - if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} - else: - rootdirs.append(root) - root = os.path.dirname(root) # up a level - - if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) - raise NotThisMethod("rootdir doesn't start with parentdir_prefix") - - -SHORT_VERSION_PY = """ -# This file was generated by 'versioneer.py' (0.18) from -# revision-control system data, or from the parent directory name of an -# unpacked source archive. Distribution tarballs contain a pre-generated copy -# of this file. - -import json - -version_json = ''' -%s -''' # END VERSION_JSON - - -def get_versions(): - return json.loads(version_json) -""" - - -def versions_from_file(filename): - """Try to determine the version from _version.py if present.""" - try: - with open(filename) as f: - contents = f.read() - except EnvironmentError: - raise NotThisMethod("unable to read _version.py") - mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) - if not mo: - mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) - if not mo: - raise NotThisMethod("no version_json in _version.py") - return json.loads(mo.group(1)) - - -def write_to_version_file(filename, versions): - """Write the given version number to the given _version.py file.""" - os.unlink(filename) - contents = json.dumps(versions, sort_keys=True, - indent=1, separators=(",", ": ")) - with open(filename, "w") as f: - f.write(SHORT_VERSION_PY % contents) - - print("set %s to '%s'" % (filename, versions["version"])) - - -def plus_or_dot(pieces): - """Return a + if we don't already have one, else return a .""" - if "+" in pieces.get("closest-tag", ""): - return "." - return "+" - - -def render_pep440(pieces): - """Build up version string, with post-release "local version identifier". - - Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you - get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty - - Exceptions: - 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += plus_or_dot(pieces) - rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_pre(pieces): - """TAG[.post.devDISTANCE] -- No -dirty. - - Exceptions: - 1: no tags. 0.post.devDISTANCE - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += ".post.dev%d" % pieces["distance"] - else: - # exception #1 - rendered = "0.post.dev%d" % pieces["distance"] - return rendered - - -def render_pep440_post(pieces): - """TAG[.postDISTANCE[.dev0]+gHEX] . - - The ".dev0" means dirty. Note that .dev0 sorts backwards - (a dirty tree will appear "older" than the corresponding clean one), - but you shouldn't be releasing software with -dirty anyways. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%s" % pieces["short"] - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += "+g%s" % pieces["short"] - return rendered - - -def render_pep440_old(pieces): - """TAG[.postDISTANCE[.dev0]] . - - The ".dev0" means dirty. - - Eexceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - return rendered - - -def render_git_describe(pieces): - """TAG[-DISTANCE-gHEX][-dirty]. - - Like 'git describe --tags --dirty --always'. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render_git_describe_long(pieces): - """TAG-DISTANCE-gHEX[-dirty]. - - Like 'git describe --tags --dirty --always -long'. - The distance/hash is unconditional. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render(pieces, style): - """Render the given version pieces into the requested style.""" - if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} - - if not style or style == "default": - style = "pep440" # the default - - if style == "pep440": - rendered = render_pep440(pieces) - elif style == "pep440-pre": - rendered = render_pep440_pre(pieces) - elif style == "pep440-post": - rendered = render_pep440_post(pieces) - elif style == "pep440-old": - rendered = render_pep440_old(pieces) - elif style == "git-describe": - rendered = render_git_describe(pieces) - elif style == "git-describe-long": - rendered = render_git_describe_long(pieces) - else: - raise ValueError("unknown style '%s'" % style) - - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} - - -class VersioneerBadRootError(Exception): - """The project root directory is unknown or missing key files.""" - - -def get_versions(verbose=False): - """Get the project version from whatever source is available. - - Returns dict with two keys: 'version' and 'full'. - """ - if "versioneer" in sys.modules: - # see the discussion in cmdclass.py:get_cmdclass() - del sys.modules["versioneer"] - - root = get_root() - cfg = get_config_from_root(root) - - assert cfg.VCS is not None, "please set [versioneer]VCS= in setup.cfg" - handlers = HANDLERS.get(cfg.VCS) - assert handlers, "unrecognized VCS '%s'" % cfg.VCS - verbose = verbose or cfg.verbose - assert cfg.versionfile_source is not None, \ - "please set versioneer.versionfile_source" - assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" - - versionfile_abs = os.path.join(root, cfg.versionfile_source) - - # extract version from first of: _version.py, VCS command (e.g. 'git - # describe'), parentdir. This is meant to work for developers using a - # source checkout, for users of a tarball created by 'setup.py sdist', - # and for users of a tarball/zipball created by 'git archive' or github's - # download-from-tag feature or the equivalent in other VCSes. - - get_keywords_f = handlers.get("get_keywords") - from_keywords_f = handlers.get("keywords") - if get_keywords_f and from_keywords_f: - try: - keywords = get_keywords_f(versionfile_abs) - ver = from_keywords_f(keywords, cfg.tag_prefix, verbose) - if verbose: - print("got version from expanded keyword %s" % ver) - return ver - except NotThisMethod: - pass - - try: - ver = versions_from_file(versionfile_abs) - if verbose: - print("got version from file %s %s" % (versionfile_abs, ver)) - return ver - except NotThisMethod: - pass - - from_vcs_f = handlers.get("pieces_from_vcs") - if from_vcs_f: - try: - pieces = from_vcs_f(cfg.tag_prefix, root, verbose) - ver = render(pieces, cfg.style) - if verbose: - print("got version from VCS %s" % ver) - return ver - except NotThisMethod: - pass - - try: - if cfg.parentdir_prefix: - ver = versions_from_parentdir(cfg.parentdir_prefix, root, verbose) - if verbose: - print("got version from parentdir %s" % ver) - return ver - except NotThisMethod: - pass - - if verbose: - print("unable to compute version") - - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, "error": "unable to compute version", - "date": None} - - -def get_version(): - """Get the short version string for this project.""" - return get_versions()["version"] - - -def get_cmdclass(): - """Get the custom setuptools/distutils subclasses used by Versioneer.""" - if "versioneer" in sys.modules: - del sys.modules["versioneer"] - # this fixes the "python setup.py develop" case (also 'install' and - # 'easy_install .'), in which subdependencies of the main project are - # built (using setup.py bdist_egg) in the same python process. Assume - # a main project A and a dependency B, which use different versions - # of Versioneer. A's setup.py imports A's Versioneer, leaving it in - # sys.modules by the time B's setup.py is executed, causing B to run - # with the wrong versioneer. Setuptools wraps the sub-dep builds in a - # sandbox that restores sys.modules to it's pre-build state, so the - # parent is protected against the child's "import versioneer". By - # removing ourselves from sys.modules here, before the child build - # happens, we protect the child from the parent's versioneer too. - # Also see https://github.com/warner/python-versioneer/issues/52 - - cmds = {} - - # we add "version" to both distutils and setuptools - from distutils.core import Command - - class cmd_version(Command): - description = "report generated version string" - user_options = [] - boolean_options = [] - - def initialize_options(self): - pass - - def finalize_options(self): - pass - - def run(self): - vers = get_versions(verbose=True) - print("Version: %s" % vers["version"]) - print(" full-revisionid: %s" % vers.get("full-revisionid")) - print(" dirty: %s" % vers.get("dirty")) - print(" date: %s" % vers.get("date")) - if vers["error"]: - print(" error: %s" % vers["error"]) - cmds["version"] = cmd_version - - # we override "build_py" in both distutils and setuptools - # - # most invocation pathways end up running build_py: - # distutils/build -> build_py - # distutils/install -> distutils/build ->.. - # setuptools/bdist_wheel -> distutils/install ->.. - # setuptools/bdist_egg -> distutils/install_lib -> build_py - # setuptools/install -> bdist_egg ->.. - # setuptools/develop -> ? - # pip install: - # copies source tree to a tempdir before running egg_info/etc - # if .git isn't copied too, 'git describe' will fail - # then does setup.py bdist_wheel, or sometimes setup.py install - # setup.py egg_info -> ? - - # we override different "build_py" commands for both environments - if "setuptools" in sys.modules: - from setuptools.command.build_py import build_py as _build_py - else: - from distutils.command.build_py import build_py as _build_py - - class cmd_build_py(_build_py): - def run(self): - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() - _build_py.run(self) - # now locate _version.py in the new build/ directory and replace - # it with an updated value - if cfg.versionfile_build: - target_versionfile = os.path.join(self.build_lib, - cfg.versionfile_build) - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) - cmds["build_py"] = cmd_build_py - - if "cx_Freeze" in sys.modules: # cx_freeze enabled? - from cx_Freeze.dist import build_exe as _build_exe - # nczeczulin reports that py2exe won't like the pep440-style string - # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. - # setup(console=[{ - # "version": versioneer.get_version().split("+", 1)[0], # FILEVERSION - # "product_version": versioneer.get_version(), - # ... - - class cmd_build_exe(_build_exe): - def run(self): - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() - target_versionfile = cfg.versionfile_source - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) - - _build_exe.run(self) - os.unlink(target_versionfile) - with open(cfg.versionfile_source, "w") as f: - LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - cmds["build_exe"] = cmd_build_exe - del cmds["build_py"] - - if 'py2exe' in sys.modules: # py2exe enabled? - try: - from py2exe.distutils_buildexe import py2exe as _py2exe # py3 - except ImportError: - from py2exe.build_exe import py2exe as _py2exe # py2 - - class cmd_py2exe(_py2exe): - def run(self): - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() - target_versionfile = cfg.versionfile_source - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) - - _py2exe.run(self) - os.unlink(target_versionfile) - with open(cfg.versionfile_source, "w") as f: - LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - cmds["py2exe"] = cmd_py2exe - - # we override different "sdist" commands for both environments - if "setuptools" in sys.modules: - from setuptools.command.sdist import sdist as _sdist - else: - from distutils.command.sdist import sdist as _sdist - - class cmd_sdist(_sdist): - def run(self): - versions = get_versions() - self._versioneer_generated_versions = versions - # unless we update this, the command will keep using the old - # version - self.distribution.metadata.version = versions["version"] - return _sdist.run(self) - - def make_release_tree(self, base_dir, files): - root = get_root() - cfg = get_config_from_root(root) - _sdist.make_release_tree(self, base_dir, files) - # now locate _version.py in the new base_dir directory - # (remembering that it may be a hardlink) and replace it with an - # updated value - target_versionfile = os.path.join(base_dir, cfg.versionfile_source) - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, - self._versioneer_generated_versions) - cmds["sdist"] = cmd_sdist - - return cmds - - -CONFIG_ERROR = """ -setup.cfg is missing the necessary Versioneer configuration. You need -a section like: - - [versioneer] - VCS = git - style = pep440 - versionfile_source = src/myproject/_version.py - versionfile_build = myproject/_version.py - tag_prefix = - parentdir_prefix = myproject- - -You will also need to edit your setup.py to use the results: - - import versioneer - setup(version=versioneer.get_version(), - cmdclass=versioneer.get_cmdclass(), ...) - -Please read the docstring in ./versioneer.py for configuration instructions, -edit setup.cfg, and re-run the installer or 'python versioneer.py setup'. -""" - -SAMPLE_CONFIG = """ -# See the docstring in versioneer.py for instructions. Note that you must -# re-run 'versioneer.py setup' after changing this section, and commit the -# resulting files. - -[versioneer] -#VCS = git -#style = pep440 -#versionfile_source = -#versionfile_build = -#tag_prefix = -#parentdir_prefix = - -""" - -INIT_PY_SNIPPET = """ -from ._version import get_versions -__version__ = get_versions()['version'] -del get_versions -""" - - -def do_setup(): - """Main VCS-independent setup function for installing Versioneer.""" - root = get_root() - try: - cfg = get_config_from_root(root) - except (EnvironmentError, configparser.NoSectionError, - configparser.NoOptionError) as e: - if isinstance(e, (EnvironmentError, configparser.NoSectionError)): - print("Adding sample versioneer config to setup.cfg", - file=sys.stderr) - with open(os.path.join(root, "setup.cfg"), "a") as f: - f.write(SAMPLE_CONFIG) - print(CONFIG_ERROR, file=sys.stderr) - return 1 - - print(" creating %s" % cfg.versionfile_source) - with open(cfg.versionfile_source, "w") as f: - LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - - ipy = os.path.join(os.path.dirname(cfg.versionfile_source), - "__init__.py") - if os.path.exists(ipy): - try: - with open(ipy, "r") as f: - old = f.read() - except EnvironmentError: - old = "" - if INIT_PY_SNIPPET not in old: - print(" appending to %s" % ipy) - with open(ipy, "a") as f: - f.write(INIT_PY_SNIPPET) - else: - print(" %s unmodified" % ipy) - else: - print(" %s doesn't exist, ok" % ipy) - ipy = None - - # Make sure both the top-level "versioneer.py" and versionfile_source - # (PKG/_version.py, used by runtime code) are in MANIFEST.in, so - # they'll be copied into source distributions. Pip won't be able to - # install the package without this. - manifest_in = os.path.join(root, "MANIFEST.in") - simple_includes = set() - try: - with open(manifest_in, "r") as f: - for line in f: - if line.startswith("include "): - for include in line.split()[1:]: - simple_includes.add(include) - except EnvironmentError: - pass - # That doesn't cover everything MANIFEST.in can do - # (http://docs.python.org/2/distutils/sourcedist.html#commands), so - # it might give some false negatives. Appending redundant 'include' - # lines is safe, though. - if "versioneer.py" not in simple_includes: - print(" appending 'versioneer.py' to MANIFEST.in") - with open(manifest_in, "a") as f: - f.write("include versioneer.py\n") - else: - print(" 'versioneer.py' already in MANIFEST.in") - if cfg.versionfile_source not in simple_includes: - print(" appending versionfile_source ('%s') to MANIFEST.in" % - cfg.versionfile_source) - with open(manifest_in, "a") as f: - f.write("include %s\n" % cfg.versionfile_source) - else: - print(" versionfile_source already in MANIFEST.in") - - # Make VCS-specific changes. For git, this means creating/changing - # .gitattributes to mark _version.py for export-subst keyword - # substitution. - do_vcs_install(manifest_in, cfg.versionfile_source, ipy) - return 0 - - -def scan_setup_py(): - """Validate the contents of setup.py against Versioneer's expectations.""" - found = set() - setters = False - errors = 0 - with open("setup.py", "r") as f: - for line in f.readlines(): - if "import versioneer" in line: - found.add("import") - if "versioneer.get_cmdclass()" in line: - found.add("cmdclass") - if "versioneer.get_version()" in line: - found.add("get_version") - if "versioneer.VCS" in line: - setters = True - if "versioneer.versionfile_source" in line: - setters = True - if len(found) != 3: - print("") - print("Your setup.py appears to be missing some important items") - print("(but I might be wrong). Please make sure it has something") - print("roughly like the following:") - print("") - print(" import versioneer") - print(" setup( version=versioneer.get_version(),") - print(" cmdclass=versioneer.get_cmdclass(), ...)") - print("") - errors += 1 - if setters: - print("You should remove lines like 'versioneer.VCS = ' and") - print("'versioneer.versionfile_source = ' . This configuration") - print("now lives in setup.cfg, and should be removed from setup.py") - print("") - errors += 1 - return errors - - -if __name__ == "__main__": - cmd = sys.argv[1] - if cmd == "setup": - errors = do_setup() - errors += scan_setup_py() - if errors: - sys.exit(1) diff --git a/external-deps/python-language-server/vscode-client/.gitignore b/external-deps/python-language-server/vscode-client/.gitignore deleted file mode 100644 index 3dc9acd2bf2..00000000000 --- a/external-deps/python-language-server/vscode-client/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -out -server -node_modules -.vscode-dev \ No newline at end of file diff --git a/external-deps/python-language-server/vscode-client/.vscodeignore b/external-deps/python-language-server/vscode-client/.vscodeignore deleted file mode 100644 index 93e28ff2fdf..00000000000 --- a/external-deps/python-language-server/vscode-client/.vscodeignore +++ /dev/null @@ -1,9 +0,0 @@ -.vscode/** -typings/** -out/test/** -test/** -src/** -**/*.map -.gitignore -tsconfig.json -vsc-extension-quickstart.md diff --git a/external-deps/python-language-server/vscode-client/License.txt b/external-deps/python-language-server/vscode-client/License.txt deleted file mode 100644 index 8e1db2929e4..00000000000 --- a/external-deps/python-language-server/vscode-client/License.txt +++ /dev/null @@ -1,11 +0,0 @@ -Copyright (c) Microsoft Corporation - -All rights reserved. - -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/external-deps/python-language-server/vscode-client/README.md b/external-deps/python-language-server/vscode-client/README.md deleted file mode 100644 index f9f3bf4e54e..00000000000 --- a/external-deps/python-language-server/vscode-client/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# vscode-client - -The vscode-client extension for Visual Studio Code helps you develop -and debug language servers. It lets you run multiple language servers -at once with minimal extra configuration per language. - -## Using this extension - - -1. Follow the [Develop against VS Code instructions](/../../#develop-against-vs-code) -1. Open a `.py` file and hover over text to start using the Python language server. - -To view a language server's stderr output in VSCode, select View → Output. -To debug further, see the "Hacking on this extension" section below. - -After updating the binary for a language server (during development or after an upgrade), just kill the process (e.g., `killall pyls`). -VSCode will automatically restart and reconnect to the language server process. - -> **Note for those who use VSCode as their primary editor:** Because this extension's functionality conflicts with other VSCode extensions -(e.g., showing Python hover information), the `yarn run vscode` script launches a separate instance of VSCode and stores its config in `../.vscode-dev`. -It will still show your existing extensions in the panel (which seems to be a VSCode bug), but they won't be activated. - -## Adding a language server - -Register your language server at the bottom of [`extension.ts`](src/extension.ts). - -## Hacking on this extension - -1. Run `yarn install` in this directory (`vscode-client`). -1. Open this directory by itself in Visual Studio Code. -1. Hit F5 to open a new VSCode instance in a debugger running this extension. (This is equivalent to going to the Debug pane on the left and running the "Launch Extension" task.) - -See the [Node.js example language server tutorial](https://code.visualstudio.com/docs/extensions/example-language-server) under "To test the language server" for more information. diff --git a/external-deps/python-language-server/vscode-client/ThirdPartyNotices.txt b/external-deps/python-language-server/vscode-client/ThirdPartyNotices.txt deleted file mode 100644 index 80a9d602af8..00000000000 --- a/external-deps/python-language-server/vscode-client/ThirdPartyNotices.txt +++ /dev/null @@ -1,31 +0,0 @@ -THIRD-PARTY SOFTWARE NOTICES AND INFORMATION -For Microsoft vscode-languageserver-node-example - -This project incorporates material from the project(s) listed below (collectively, “Third Party Code”). -Microsoft is not the original author of the Third Party Code. The original copyright notice and license -under which Microsoft received such Third Party Code are set out below. This Third Party Code is licensed -to you under their original license terms set forth below. Microsoft reserves all other rights not expressly -granted, whether by implication, estoppel or otherwise. - -1. DefinitelyTyped version 0.0.1 (https://github.com/borisyankov/DefinitelyTyped) - -This project is licensed under the MIT license. -Copyrights are respective of each contributor listed at the beginning of each definition file. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/external-deps/python-language-server/vscode-client/package.json b/external-deps/python-language-server/vscode-client/package.json deleted file mode 100644 index eb4faeeaa89..00000000000 --- a/external-deps/python-language-server/vscode-client/package.json +++ /dev/null @@ -1,296 +0,0 @@ -{ - "name": "pyls", - "description": "Python language server", - "author": "Sourcegraph", - "repository": "https://github.com/Microsoft/vscode-languageserver-node", - "license": "MIT", - "version": "0.0.1", - "publisher": "sqs", - "engines": { - "vscode": "^1.15.0" - }, - "categories": [ - "Other" - ], - "activationEvents": [ - "*" - ], - "contributes": { - "configuration": { - "title": "Python Language Server Configuration", - "type": "object", - "properties": { - "pyls.executable": { - "type": "string", - "default": "pyls", - "description": "Language server executable" - }, - "pyls.configurationSources": { - "type": "array", - "default": ["pycodestyle"], - "description": "List of configuration sources to use.", - "items": { - "type": "string", - "enum": ["pycodestyle", "pyflakes"] - }, - "uniqueItems": true - }, - "pyls.plugins.jedi.extra_paths": { - "type": "array", - "default": [], - "description": "Define extra paths for jedi.Script." - }, - "pyls.plugins.jedi.environment": { - "type": "string", - "default": null, - "description": "Define environment for jedi.Script and Jedi.names." - }, - "pyls.plugins.jedi_completion.enabled": { - "type": "boolean", - "default": true, - "description": "Enable or disable the plugin." - }, - "pyls.plugins.jedi_completion.include_params": { - "type": "boolean", - "default": true, - "description": "Auto-completes methods and classes with tabstops for each parameter." - }, - "pyls.plugins.jedi_definition.enabled": { - "type": "boolean", - "default": true, - "description": "Enable or disable the plugin." - }, - "pyls.plugins.jedi_definition.follow_imports": { - "type": "boolean", - "default": true, - "description": "The goto call will follow imports." - }, - "pyls.plugins.jedi_definition.follow_builtin_imports": { - "type": "boolean", - "default": true, - "description": "If follow_imports is True will decide if it follow builtin imports." - }, - "pyls.plugins.jedi_hover.enabled": { - "type": "boolean", - "default": true, - "description": "Enable or disable the plugin." - }, - "pyls.plugins.jedi_references.enabled": { - "type": "boolean", - "default": true, - "description": "Enable or disable the plugin." - }, - "pyls.plugins.jedi_signature_help.enabled": { - "type": "boolean", - "default": true, - "description": "Enable or disable the plugin." - }, - "pyls.plugins.jedi_symbols.enabled": { - "type": "boolean", - "default": true, - "description": "Enable or disable the plugin." - }, - "pyls.plugins.jedi_symbols.all_scopes": { - "type": "boolean", - "default": true, - "description": "If True lists the names of all scopes instead of only the module namespace." - }, - "pyls.plugins.mccabe.enabled": { - "type": "boolean", - "default": true, - "description": "Enable or disable the plugin." - }, - "pyls.plugins.mccabe.threshold": { - "type": "number", - "default": 15, - "description": "The minimum threshold that triggers warnings about cyclomatic complexity." - }, - "pyls.plugins.preload.enabled": { - "type": "boolean", - "default": true, - "description": "Enable or disable the plugin." - }, - "pyls.plugins.preload.modules": { - "type": "array", - "default": null, - "items": { - "type": "string" - }, - "uniqueItems": true, - "description": "List of modules to import on startup" - }, - "pyls.plugins.pycodestyle.enabled": { - "type": "boolean", - "default": true, - "description": "Enable or disable the plugin." - }, - "pyls.plugins.pycodestyle.exclude": { - "type": "array", - "default": null, - "items": { - "type": "string" - }, - "uniqueItems": true, - "description": "Exclude files or directories which match these patterns." - }, - "pyls.plugins.pycodestyle.filename": { - "type": "array", - "default": null, - "items": { - "type": "string" - }, - "uniqueItems": true, - "description": "When parsing directories, only check filenames matching these patterns." - }, - "pyls.plugins.pycodestyle.select": { - "type": "array", - "default": null, - "items": { - "type": "string" - }, - "uniqueItems": true, - "description": "Select errors and warnings" - }, - "pyls.plugins.pycodestyle.ignore": { - "type": "array", - "default": null, - "items": { - "type": "string" - }, - "uniqueItems": true, - "description": "Ignore errors and warnings" - }, - "pyls.plugins.pycodestyle.hangClosing": { - "type": "boolean", - "default": null, - "description": "Hang closing bracket instead of matching indentation of opening bracket's line." - }, - "pyls.plugins.pycodestyle.maxLineLength": { - "type": "number", - "default": null, - "description": "Set maximum allowed line length." - }, - "pyls.plugins.pydocstyle.enabled": { - "type": "boolean", - "default": false, - "description": "Enable or disable the plugin." - }, - "pyls.plugins.pydocstyle.convention": { - "type": "string", - "default": null, - "enum": [ - "pep257", - "numpy" - ], - "description": "Choose the basic list of checked errors by specifying an existing convention." - }, - "pyls.plugins.pydocstyle.addIgnore": { - "type": "array", - "default": null, - "items": { - "type": "string" - }, - "uniqueItems": true, - "description": "Ignore errors and warnings in addition to the specified convention." - }, - "pyls.plugins.pydocstyle.addSelect": { - "type": "array", - "default": null, - "items": { - "type": "string" - }, - "uniqueItems": true, - "description": "Select errors and warnings in addition to the specified convention." - }, - "pyls.plugins.pydocstyle.ignore": { - "type": "array", - "default": null, - "items": { - "type": "string" - }, - "uniqueItems": true, - "description": "Ignore errors and warnings" - }, - "pyls.plugins.pydocstyle.select": { - "type": "array", - "default": null, - "items": { - "type": "string" - }, - "uniqueItems": true, - "description": "Select errors and warnings" - }, - "pyls.plugins.pydocstyle.match": { - "type": "string", - "default": "(?!test_).*\\.py", - "description": "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'." - }, - "pyls.plugins.pydocstyle.matchDir": { - "type": "string", - "default": "[^\\.].*", - "description": "Search only dirs that exactly match the given regular expression; default is to match dirs which do not begin with a dot." - }, - "pyls.plugins.pyflakes.enabled": { - "type": "boolean", - "default": true, - "description": "Enable or disable the plugin." - }, - "pyls.plugins.pylint.enabled": { - "type": "boolean", - "default": false, - "description": "Enable or disable the plugin." - }, - "pyls.plugins.pylint.args": { - "type": "array", - "default": null, - "items": { - "type": "string" - }, - "uniqueItems": false, - "description": "Arguments to pass to pylint." - }, - "pyls.plugins.rope_completion.enabled": { - "type": "boolean", - "default": true, - "description": "Enable or disable the plugin." - }, - "pyls.plugins.yapf.enabled": { - "type": "boolean", - "default": true, - "description": "Enable or disable the plugin." - }, - "pyls.rope.extensionModules": { - "type": "string", - "default": null, - "description": "Builtin and c-extension modules that are allowed to be imported and inspected by rope." - }, - "pyls.rope.ropeFolder": { - "type": "array", - "default": null, - "items": { - "type": "string" - }, - "uniqueItems": true, - "description": "The name of the folder in which rope stores project configurations and data. Pass `null` for not using such a folder at all." - } - } - } - }, - "main": "./out/extension", - "scripts": { - "vscode:prepublish": "tsc -p ./", - "compile": "tsc -watch -p ./", - "postinstall": "node ./node_modules/vscode/bin/install", - "vscode": "npm run vscode:prepublish && VSCODE=$(which code-insiders || which code || echo echo ERROR: neither the code nor code-insiders vscode executable is installed); USER=dummy-dont-share-vscode-instance $VSCODE --user-data-dir=$PWD/.vscode-dev/user-data --extensionHomePath=$PWD/.vscode-dev/extensions --extensionDevelopmentPath=$PWD $*" - }, - "devDependencies": { - "typescript": "^2.3.4", - "vscode": "^1.1.4", - "mocha": "^2.3.3", - "@types/node": "^6.0.40", - "@types/mocha": "^2.2.32" - }, - "dependencies": { - "vscode-languageclient": "^3.4.5" - } -} diff --git a/external-deps/python-language-server/vscode-client/src/extension.ts b/external-deps/python-language-server/vscode-client/src/extension.ts deleted file mode 100644 index 5816f9df415..00000000000 --- a/external-deps/python-language-server/vscode-client/src/extension.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* -------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - * ------------------------------------------------------------------------------------------ */ -'use strict'; - -import * as net from 'net'; - -import { workspace, Disposable, ExtensionContext } from 'vscode'; -import { LanguageClient, LanguageClientOptions, SettingMonitor, ServerOptions, ErrorAction, ErrorHandler, CloseAction, TransportKind } from 'vscode-languageclient'; - -function startLangServer(command: string, args: string[], documentSelector: string[]): Disposable { - const serverOptions: ServerOptions = { - command, - args, - }; - const clientOptions: LanguageClientOptions = { - documentSelector: documentSelector, - synchronize: { - configurationSection: "pyls" - } - } - return new LanguageClient(command, serverOptions, clientOptions).start(); -} - -function startLangServerTCP(addr: number, documentSelector: string[]): Disposable { - const serverOptions: ServerOptions = function() { - return new Promise((resolve, reject) => { - var client = new net.Socket(); - client.connect(addr, "127.0.0.1", function() { - resolve({ - reader: client, - writer: client - }); - }); - }); - } - - const clientOptions: LanguageClientOptions = { - documentSelector: documentSelector, - } - return new LanguageClient(`tcp lang server (port ${addr})`, serverOptions, clientOptions).start(); -} - -export function activate(context: ExtensionContext) { - const executable = workspace.getConfiguration("pyls").get("executable"); - context.subscriptions.push(startLangServer(executable, ["-vv"], ["python"])); - // For TCP server needs to be started seperately - // context.subscriptions.push(startLangServerTCP(2087, ["python"])); -} - diff --git a/external-deps/python-language-server/vscode-client/tsconfig.json b/external-deps/python-language-server/vscode-client/tsconfig.json deleted file mode 100644 index a9142181413..00000000000 --- a/external-deps/python-language-server/vscode-client/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es6", - "outDir": "out", - "lib": [ "es6" ], - "sourceMap": true - }, - "exclude": [ - "node_modules", - "server" - ] -} diff --git a/external-deps/python-language-server/vscode-client/yarn.lock b/external-deps/python-language-server/vscode-client/yarn.lock deleted file mode 100644 index 01b11c89726..00000000000 --- a/external-deps/python-language-server/vscode-client/yarn.lock +++ /dev/null @@ -1,1821 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@types/mocha@^2.2.32": - version "2.2.46" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.46.tgz#b04713f7759d1cf752effdaae7b3969e285ebc16" - -"@types/node@^6.0.40": - version "6.0.96" - resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.96.tgz#7bf0bf40d6ce51e93762cc47d010c8cc5ebb2179" - -ajv@^5.1.0: - version "5.5.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" - dependencies: - co "^4.6.0" - fast-deep-equal "^1.0.0" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.3.0" - -ansi-cyan@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ansi-cyan/-/ansi-cyan-0.1.1.tgz#538ae528af8982f28ae30d86f2f17456d2609873" - dependencies: - ansi-wrap "0.1.0" - -ansi-gray@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251" - dependencies: - ansi-wrap "0.1.0" - -ansi-red@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ansi-red/-/ansi-red-0.1.1.tgz#8c638f9d1080800a353c9c28c8a81ca4705d946c" - dependencies: - ansi-wrap "0.1.0" - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - -ansi-wrap@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" - -arr-diff@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-1.1.0.tgz#687c32758163588fef7de7b36fabe495eb1a399a" - dependencies: - arr-flatten "^1.0.1" - array-slice "^0.2.3" - -arr-diff@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - dependencies: - arr-flatten "^1.0.1" - -arr-flatten@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - -arr-union@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-2.1.0.tgz#20f9eab5ec70f5c7d215b1077b1c39161d292c7d" - -array-differ@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" - -array-slice@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" - -array-union@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - dependencies: - array-uniq "^1.0.1" - -array-uniq@^1.0.1, array-uniq@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - -array-unique@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" - -arrify@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - -asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - -assert-plus@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - -aws-sign2@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - -aws4@^1.2.1, aws4@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - -bcrypt-pbkdf@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" - dependencies: - tweetnacl "^0.14.3" - -beeper@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809" - -block-stream@*: - version "0.0.9" - resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - dependencies: - inherits "~2.0.0" - -boom@2.x.x: - version "2.10.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" - dependencies: - hoek "2.x.x" - -boom@4.x.x: - version "4.3.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" - dependencies: - hoek "4.x.x" - -boom@5.x.x: - version "5.2.0" - resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" - dependencies: - hoek "4.x.x" - -brace-expansion@^1.1.7: - version "1.1.8" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^1.8.2: - version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - dependencies: - expand-range "^1.8.1" - preserve "^0.2.0" - repeat-element "^1.1.2" - -browser-stdout@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" - -buffer-crc32@~0.2.3: - version "0.2.13" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - -caseless@~0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - -chalk@^1.0.0, chalk@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -clone-buffer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" - -clone-stats@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" - -clone-stats@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" - -clone@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" - -clone@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.3.tgz#298d7e2231660f40c003c2ed3140decf3f53085f" - -clone@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" - -cloneable-readable@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.0.0.tgz#a6290d413f217a61232f95e458ff38418cfb0117" - dependencies: - inherits "^2.0.1" - process-nextick-args "^1.0.6" - through2 "^2.0.1" - -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - -color-support@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" - -combined-stream@^1.0.5, combined-stream@~1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" - dependencies: - delayed-stream "~1.0.0" - -commander@0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" - -commander@2.11.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" - -commander@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" - -commander@^2.9.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - -convert-source-map@^1.1.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" - -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - -cryptiles@2.x.x: - version "2.0.5" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" - dependencies: - boom "2.x.x" - -cryptiles@3.x.x: - version "3.1.2" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" - dependencies: - boom "5.x.x" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - dependencies: - assert-plus "^1.0.0" - -dateformat@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062" - -debug@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" - dependencies: - ms "0.7.1" - -debug@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - dependencies: - ms "2.0.0" - -deep-assign@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/deep-assign/-/deep-assign-1.0.0.tgz#b092743be8427dc621ea0067cdec7e70dd19f37b" - dependencies: - is-obj "^1.0.0" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - -diff@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" - -diff@3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" - -duplexer2@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" - dependencies: - readable-stream "~1.1.9" - -duplexer@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" - -duplexify@^3.2.0: - version "3.5.3" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.3.tgz#8b5818800df92fd0125b27ab896491912858243e" - dependencies: - end-of-stream "^1.0.0" - inherits "^2.0.1" - readable-stream "^2.0.0" - stream-shift "^1.0.0" - -ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" - dependencies: - jsbn "~0.1.0" - -end-of-stream@^1.0.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" - dependencies: - once "^1.4.0" - -escape-string-regexp@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" - -escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - -event-stream@^3.3.1, event-stream@~3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" - dependencies: - duplexer "~0.1.1" - from "~0" - map-stream "~0.1.0" - pause-stream "0.0.11" - split "0.3" - stream-combiner "~0.0.4" - through "~2.3.1" - -expand-brackets@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - dependencies: - is-posix-bracket "^0.1.0" - -expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - dependencies: - fill-range "^2.1.0" - -extend-shallow@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-1.1.4.tgz#19d6bf94dfc09d76ba711f39b872d21ff4dd9071" - dependencies: - kind-of "^1.1.0" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - dependencies: - is-extendable "^0.1.0" - -extend@^3.0.0, extend@~3.0.0, extend@~3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" - -extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - dependencies: - is-extglob "^1.0.0" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - -fancy-log@^1.1.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.2.tgz#f41125e3d84f2e7d89a43d06d958c8f78be16be1" - dependencies: - ansi-gray "^0.1.1" - color-support "^1.1.3" - time-stamp "^1.0.0" - -fast-deep-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" - -fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - -fd-slicer@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" - dependencies: - pend "~1.2.0" - -filename-regex@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" - -fill-range@^2.1.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" - dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^1.1.3" - repeat-element "^1.1.2" - repeat-string "^1.5.2" - -first-chunk-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e" - -for-in@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - -for-own@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - dependencies: - for-in "^1.0.1" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - -form-data@~2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" - -form-data@~2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" - -from@~0: - version "0.1.7" - resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - -fstream@^1.0.2: - version "1.0.11" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" - dependencies: - graceful-fs "^4.1.2" - inherits "~2.0.0" - mkdirp ">=0.5 0" - rimraf "2" - -generate-function@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" - -generate-object-property@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" - dependencies: - is-property "^1.0.0" - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - dependencies: - assert-plus "^1.0.0" - -glob-base@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - dependencies: - glob-parent "^2.0.0" - is-glob "^2.0.0" - -glob-parent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - dependencies: - is-glob "^2.0.0" - -glob-parent@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" - -glob-stream@^5.3.2: - version "5.3.5" - resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-5.3.5.tgz#a55665a9a8ccdc41915a87c701e32d4e016fad22" - dependencies: - extend "^3.0.0" - glob "^5.0.3" - glob-parent "^3.0.0" - micromatch "^2.3.7" - ordered-read-streams "^0.3.0" - through2 "^0.6.0" - to-absolute-glob "^0.1.1" - unique-stream "^2.0.2" - -glob@3.2.11: - version "3.2.11" - resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d" - dependencies: - inherits "2" - minimatch "0.3" - -glob@7.1.2, glob@^7.0.5, glob@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glob@^5.0.3: - version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - -glogg@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.0.tgz#7fe0f199f57ac906cf512feead8f90ee4a284fc5" - dependencies: - sparkles "^1.0.0" - -graceful-fs@^4.0.0, graceful-fs@^4.1.2: - version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - -growl@1.10.3: - version "1.10.3" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.3.tgz#1926ba90cf3edfe2adb4927f5880bc22c66c790f" - -growl@1.9.2: - version "1.9.2" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" - -gulp-chmod@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/gulp-chmod/-/gulp-chmod-2.0.0.tgz#00c390b928a0799b251accf631aa09e01cc6299c" - dependencies: - deep-assign "^1.0.0" - stat-mode "^0.2.0" - through2 "^2.0.0" - -gulp-filter@^5.0.1: - version "5.1.0" - resolved "https://registry.yarnpkg.com/gulp-filter/-/gulp-filter-5.1.0.tgz#a05e11affb07cf7dcf41a7de1cb7b63ac3783e73" - dependencies: - multimatch "^2.0.0" - plugin-error "^0.1.2" - streamfilter "^1.0.5" - -gulp-gunzip@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gulp-gunzip/-/gulp-gunzip-1.0.0.tgz#15b741145e83a9c6f50886241b57cc5871f151a9" - dependencies: - through2 "~0.6.5" - vinyl "~0.4.6" - -gulp-remote-src@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/gulp-remote-src/-/gulp-remote-src-0.4.3.tgz#5728cfd643433dd4845ddef0969f0f971a2ab4a1" - dependencies: - event-stream "~3.3.4" - node.extend "~1.1.2" - request "~2.79.0" - through2 "~2.0.3" - vinyl "~2.0.1" - -gulp-sourcemaps@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz#b86ff349d801ceb56e1d9e7dc7bbcb4b7dee600c" - dependencies: - convert-source-map "^1.1.1" - graceful-fs "^4.1.2" - strip-bom "^2.0.0" - through2 "^2.0.0" - vinyl "^1.0.0" - -gulp-symdest@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/gulp-symdest/-/gulp-symdest-1.1.0.tgz#c165320732d192ce56fd94271ffa123234bf2ae0" - dependencies: - event-stream "^3.3.1" - mkdirp "^0.5.1" - queue "^3.1.0" - vinyl-fs "^2.4.3" - -gulp-untar@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/gulp-untar/-/gulp-untar-0.0.6.tgz#d6bdefde7e9a8e054c9f162385a0782c4be74000" - dependencies: - event-stream "~3.3.4" - gulp-util "~3.0.8" - streamifier "~0.1.1" - tar "^2.2.1" - through2 "~2.0.3" - -gulp-util@~3.0.8: - version "3.0.8" - resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f" - dependencies: - array-differ "^1.0.0" - array-uniq "^1.0.2" - beeper "^1.0.0" - chalk "^1.0.0" - dateformat "^2.0.0" - fancy-log "^1.1.0" - gulplog "^1.0.0" - has-gulplog "^0.1.0" - lodash._reescape "^3.0.0" - lodash._reevaluate "^3.0.0" - lodash._reinterpolate "^3.0.0" - lodash.template "^3.0.0" - minimist "^1.1.0" - multipipe "^0.1.2" - object-assign "^3.0.0" - replace-ext "0.0.1" - through2 "^2.0.0" - vinyl "^0.5.0" - -gulp-vinyl-zip@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/gulp-vinyl-zip/-/gulp-vinyl-zip-2.1.0.tgz#24e40685dc05b7149995245099e0590263be8dad" - dependencies: - event-stream "^3.3.1" - queue "^4.2.1" - through2 "^2.0.3" - vinyl "^2.0.2" - vinyl-fs "^2.0.0" - yauzl "^2.2.1" - yazl "^2.2.1" - -gulplog@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5" - dependencies: - glogg "^1.0.0" - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - -har-validator@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" - dependencies: - chalk "^1.1.1" - commander "^2.9.0" - is-my-json-valid "^2.12.4" - pinkie-promise "^2.0.0" - -har-validator@~5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" - dependencies: - ajv "^5.1.0" - har-schema "^2.0.0" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - dependencies: - ansi-regex "^2.0.0" - -has-flag@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" - -has-gulplog@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce" - dependencies: - sparkles "^1.0.0" - -hawk@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" - -hawk@~6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" - dependencies: - boom "4.x.x" - cryptiles "3.x.x" - hoek "4.x.x" - sntp "2.x.x" - -he@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" - -hoek@2.x.x: - version "2.16.3" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" - -hoek@4.x.x: - version "4.2.0" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" - -http-signature@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" - dependencies: - assert-plus "^0.2.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - -is-dotfile@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - -is-equal-shallow@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - dependencies: - is-primitive "^2.0.0" - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - -is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - -is-extglob@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - -is-glob@^2.0.0, is-glob@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - dependencies: - is-extglob "^1.0.0" - -is-glob@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - dependencies: - is-extglob "^2.1.0" - -is-my-json-valid@^2.12.4: - version "2.17.1" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.1.tgz#3da98914a70a22f0a8563ef1511a246c6fc55471" - dependencies: - generate-function "^2.0.0" - generate-object-property "^1.1.0" - jsonpointer "^4.0.0" - xtend "^4.0.0" - -is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - dependencies: - kind-of "^3.0.2" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - dependencies: - kind-of "^3.0.2" - -is-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" - -is-posix-bracket@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - -is-primitive@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - -is-property@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - -is-stream@^1.0.1, is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - -is-utf8@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - -is-valid-glob@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-0.3.0.tgz#d4b55c69f51886f9b65c70d6c2622d37e29f48fe" - -is@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/is/-/is-3.2.1.tgz#d0ac2ad55eb7b0bec926a5266f6c662aaa83dca5" - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - -isarray@1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - dependencies: - isarray "1.0.0" - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - -jade@0.26.3: - version "0.26.3" - resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" - dependencies: - commander "0.6.1" - mkdirp "0.3.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - -json-schema-traverse@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - -json-stable-stringify@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - dependencies: - jsonify "~0.0.0" - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - -jsonpointer@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -kind-of@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44" - -kind-of@^3.0.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - dependencies: - is-buffer "^1.1.5" - -lazystream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" - dependencies: - readable-stream "^2.0.5" - -lodash._basecopy@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" - -lodash._basetostring@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5" - -lodash._basevalues@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7" - -lodash._getnative@^3.0.0: - version "3.9.1" - resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" - -lodash._isiterateecall@^3.0.0: - version "3.0.9" - resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" - -lodash._reescape@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a" - -lodash._reevaluate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed" - -lodash._reinterpolate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - -lodash._root@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" - -lodash.escape@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698" - dependencies: - lodash._root "^3.0.0" - -lodash.isarguments@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" - -lodash.isarray@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" - -lodash.isequal@^4.0.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" - -lodash.keys@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" - dependencies: - lodash._getnative "^3.0.0" - lodash.isarguments "^3.0.0" - lodash.isarray "^3.0.0" - -lodash.restparam@^3.0.0: - version "3.6.1" - resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" - -lodash.template@^3.0.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f" - dependencies: - lodash._basecopy "^3.0.0" - lodash._basetostring "^3.0.0" - lodash._basevalues "^3.0.0" - lodash._isiterateecall "^3.0.0" - lodash._reinterpolate "^3.0.0" - lodash.escape "^3.0.0" - lodash.keys "^3.0.0" - lodash.restparam "^3.0.0" - lodash.templatesettings "^3.0.0" - -lodash.templatesettings@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5" - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.escape "^3.0.0" - -lru-cache@2: - version "2.7.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" - -map-stream@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" - -merge-stream@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" - dependencies: - readable-stream "^2.0.1" - -micromatch@^2.3.7: - version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - dependencies: - arr-diff "^2.0.0" - array-unique "^0.2.1" - braces "^1.8.2" - expand-brackets "^0.1.4" - extglob "^0.3.1" - filename-regex "^2.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.1" - kind-of "^3.0.2" - normalize-path "^2.0.1" - object.omit "^2.0.0" - parse-glob "^3.0.4" - regex-cache "^0.4.2" - -mime-db@~1.30.0: - version "1.30.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" - -mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.7: - version "2.1.17" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" - dependencies: - mime-db "~1.30.0" - -minimatch@0.3: - version "0.3.0" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd" - dependencies: - lru-cache "2" - sigmund "~1.0.0" - -"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - dependencies: - brace-expansion "^1.1.7" - -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - -minimist@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - -mkdirp@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" - -mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - dependencies: - minimist "0.0.8" - -mocha@^2.3.3: - version "2.5.3" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.5.3.tgz#161be5bdeb496771eb9b35745050b622b5aefc58" - dependencies: - commander "2.3.0" - debug "2.2.0" - diff "1.4.0" - escape-string-regexp "1.0.2" - glob "3.2.11" - growl "1.9.2" - jade "0.26.3" - mkdirp "0.5.1" - supports-color "1.2.0" - to-iso-string "0.0.2" - -mocha@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-4.1.0.tgz#7d86cfbcf35cb829e2754c32e17355ec05338794" - dependencies: - browser-stdout "1.3.0" - commander "2.11.0" - debug "3.1.0" - diff "3.3.1" - escape-string-regexp "1.0.5" - glob "7.1.2" - growl "1.10.3" - he "1.1.1" - mkdirp "0.5.1" - supports-color "4.4.0" - -ms@0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - -multimatch@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-2.1.0.tgz#9c7906a22fb4c02919e2f5f75161b4cdbd4b2a2b" - dependencies: - array-differ "^1.0.0" - array-union "^1.0.1" - arrify "^1.0.0" - minimatch "^3.0.0" - -multipipe@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b" - dependencies: - duplexer2 "0.0.2" - -node.extend@~1.1.2: - version "1.1.6" - resolved "https://registry.yarnpkg.com/node.extend/-/node.extend-1.1.6.tgz#a7b882c82d6c93a4863a5504bd5de8ec86258b96" - dependencies: - is "^3.1.0" - -normalize-path@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - dependencies: - remove-trailing-separator "^1.0.1" - -oauth-sign@~0.8.1, oauth-sign@~0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - -object-assign@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" - -object-assign@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - -object.omit@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" - dependencies: - for-own "^0.1.4" - is-extendable "^0.1.1" - -once@^1.3.0, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - dependencies: - wrappy "1" - -ordered-read-streams@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz#7137e69b3298bb342247a1bbee3881c80e2fd78b" - dependencies: - is-stream "^1.0.1" - readable-stream "^2.0.1" - -parse-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - dependencies: - glob-base "^0.3.0" - is-dotfile "^1.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.0" - -path-dirname@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - -pause-stream@0.0.11: - version "0.0.11" - resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" - dependencies: - through "~2.3" - -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - -plugin-error@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace" - dependencies: - ansi-cyan "^0.1.1" - ansi-red "^0.1.1" - arr-diff "^1.0.1" - arr-union "^2.0.1" - extend-shallow "^1.1.2" - -preserve@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - -process-nextick-args@^1.0.6, process-nextick-args@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" - -punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - -qs@~6.3.0: - version "6.3.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" - -qs@~6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" - -querystringify@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb" - -queue@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/queue/-/queue-3.1.0.tgz#6c49d01f009e2256788789f2bffac6b8b9990585" - dependencies: - inherits "~2.0.0" - -queue@^4.2.1: - version "4.4.2" - resolved "https://registry.yarnpkg.com/queue/-/queue-4.4.2.tgz#5a9733d9a8b8bd1b36e934bc9c55ab89b28e29c7" - dependencies: - inherits "~2.0.0" - -randomatic@^1.1.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -"readable-stream@>=1.0.33-1 <1.1.0-0": - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.1.5: - version "2.3.3" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - safe-buffer "~5.1.1" - string_decoder "~1.0.3" - util-deprecate "~1.0.1" - -readable-stream@~1.1.9: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -regex-cache@^0.4.2: - version "0.4.4" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" - dependencies: - is-equal-shallow "^0.1.3" - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - -repeat-element@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" - -repeat-string@^1.5.2: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - -replace-ext@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" - -replace-ext@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" - -request@^2.83.0: - version "2.83.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.6.0" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" - forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" - hawk "~6.0.2" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" - performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - stringstream "~0.0.5" - tough-cookie "~2.3.3" - tunnel-agent "^0.6.0" - uuid "^3.1.0" - -request@~2.79.0: - version "2.79.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.11.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~2.0.6" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - qs "~6.3.0" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "~0.4.1" - uuid "^3.0.0" - -requires-port@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - -rimraf@2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" - dependencies: - glob "^7.0.5" - -safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" - -semver@^5.4.1: - version "5.5.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" - -sigmund@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" - -sntp@1.x.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" - dependencies: - hoek "2.x.x" - -sntp@2.x.x: - version "2.1.0" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" - dependencies: - hoek "4.x.x" - -source-map-support@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.2.tgz#1a6297fd5b2e762b39688c7fc91233b60984f0a5" - dependencies: - source-map "^0.6.0" - -source-map@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - -sparkles@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3" - -split@0.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" - dependencies: - through "2" - -sshpk@^1.7.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - optionalDependencies: - bcrypt-pbkdf "^1.0.0" - ecc-jsbn "~0.1.1" - jsbn "~0.1.0" - tweetnacl "~0.14.0" - -stat-mode@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/stat-mode/-/stat-mode-0.2.2.tgz#e6c80b623123d7d80cf132ce538f346289072502" - -stream-combiner@~0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" - dependencies: - duplexer "~0.1.1" - -stream-shift@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" - -streamfilter@^1.0.5: - version "1.0.7" - resolved "https://registry.yarnpkg.com/streamfilter/-/streamfilter-1.0.7.tgz#ae3e64522aa5a35c061fd17f67620c7653c643c9" - dependencies: - readable-stream "^2.0.2" - -streamifier@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/streamifier/-/streamifier-0.1.1.tgz#97e98d8fa4d105d62a2691d1dc07e820db8dfc4f" - -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - -string_decoder@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" - dependencies: - safe-buffer "~5.1.0" - -stringstream@~0.0.4, stringstream@~0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" - -strip-ansi@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - dependencies: - ansi-regex "^2.0.0" - -strip-bom-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz#e7144398577d51a6bed0fa1994fa05f43fd988ee" - dependencies: - first-chunk-stream "^1.0.0" - strip-bom "^2.0.0" - -strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - dependencies: - is-utf8 "^0.2.0" - -supports-color@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" - -supports-color@4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" - dependencies: - has-flag "^2.0.0" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - -tar@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" - dependencies: - block-stream "*" - fstream "^1.0.2" - inherits "2" - -through2-filter@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-2.0.0.tgz#60bc55a0dacb76085db1f9dae99ab43f83d622ec" - dependencies: - through2 "~2.0.0" - xtend "~4.0.0" - -through2@^0.6.0, through2@~0.6.5: - version "0.6.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" - dependencies: - readable-stream ">=1.0.33-1 <1.1.0-0" - xtend ">=4.0.0 <4.1.0-0" - -through2@^2.0.0, through2@^2.0.1, through2@^2.0.3, through2@~2.0.0, through2@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" - dependencies: - readable-stream "^2.1.5" - xtend "~4.0.1" - -through@2, through@~2.3, through@~2.3.1: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - -time-stamp@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" - -to-absolute-glob@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz#1cdfa472a9ef50c239ee66999b662ca0eb39937f" - dependencies: - extend-shallow "^2.0.1" - -to-iso-string@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1" - -tough-cookie@~2.3.0, tough-cookie@~2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" - dependencies: - punycode "^1.4.1" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - dependencies: - safe-buffer "^5.0.1" - -tunnel-agent@~0.4.1: - version "0.4.3" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - -typescript@^2.3.4: - version "2.6.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4" - -unique-stream@^2.0.2: - version "2.2.1" - resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.2.1.tgz#5aa003cfbe94c5ff866c4e7d668bb1c4dbadb369" - dependencies: - json-stable-stringify "^1.0.0" - through2-filter "^2.0.0" - -url-parse@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.2.0.tgz#3a19e8aaa6d023ddd27dcc44cb4fc8f7fec23986" - dependencies: - querystringify "~1.0.0" - requires-port "~1.0.0" - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - -uuid@^3.0.0, uuid@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" - -vali-date@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/vali-date/-/vali-date-1.0.0.tgz#1b904a59609fb328ef078138420934f6b86709a6" - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -vinyl-fs@^2.0.0, vinyl-fs@^2.4.3: - version "2.4.4" - resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-2.4.4.tgz#be6ff3270cb55dfd7d3063640de81f25d7532239" - dependencies: - duplexify "^3.2.0" - glob-stream "^5.3.2" - graceful-fs "^4.0.0" - gulp-sourcemaps "1.6.0" - is-valid-glob "^0.3.0" - lazystream "^1.0.0" - lodash.isequal "^4.0.0" - merge-stream "^1.0.0" - mkdirp "^0.5.0" - object-assign "^4.0.0" - readable-stream "^2.0.4" - strip-bom "^2.0.0" - strip-bom-stream "^1.0.0" - through2 "^2.0.0" - through2-filter "^2.0.0" - vali-date "^1.0.0" - vinyl "^1.0.0" - -vinyl-source-stream@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vinyl-source-stream/-/vinyl-source-stream-1.1.2.tgz#62b53a135610a896e98ca96bee3a87f008a8e780" - dependencies: - through2 "^2.0.3" - vinyl "^0.4.3" - -vinyl@^0.4.3, vinyl@~0.4.6: - version "0.4.6" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.4.6.tgz#2f356c87a550a255461f36bbeb2a5ba8bf784847" - dependencies: - clone "^0.2.0" - clone-stats "^0.0.1" - -vinyl@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde" - dependencies: - clone "^1.0.0" - clone-stats "^0.0.1" - replace-ext "0.0.1" - -vinyl@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" - dependencies: - clone "^1.0.0" - clone-stats "^0.0.1" - replace-ext "0.0.1" - -vinyl@^2.0.2: - version "2.1.0" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.1.0.tgz#021f9c2cf951d6b939943c89eb5ee5add4fd924c" - dependencies: - clone "^2.1.1" - clone-buffer "^1.0.0" - clone-stats "^1.0.0" - cloneable-readable "^1.0.0" - remove-trailing-separator "^1.0.1" - replace-ext "^1.0.0" - -vinyl@~2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.0.2.tgz#0a3713d8d4e9221c58f10ca16c0116c9e25eda7c" - dependencies: - clone "^1.0.0" - clone-buffer "^1.0.0" - clone-stats "^1.0.0" - cloneable-readable "^1.0.0" - is-stream "^1.1.0" - remove-trailing-separator "^1.0.1" - replace-ext "^1.0.0" - -vscode-jsonrpc@^3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0.tgz#87239d9e166b2d7352245b8a813597804c1d63aa" - -vscode-languageclient@^3.4.5: - version "3.5.0" - resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-3.5.0.tgz#36d02cc186a8365a4467719a290fb200a9ae490a" - dependencies: - vscode-languageserver-protocol "^3.5.0" - -vscode-languageserver-protocol@^3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0.tgz#067c5cbe27709795398d119692c97ebba1452209" - dependencies: - vscode-jsonrpc "^3.5.0" - vscode-languageserver-types "^3.5.0" - -vscode-languageserver-types@^3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0.tgz#e48d79962f0b8e02de955e3f524908e2b19c0374" - -vscode@^1.1.4: - version "1.1.10" - resolved "https://registry.yarnpkg.com/vscode/-/vscode-1.1.10.tgz#d1cba378ab24f1d3ddf9cd470d242ee1472dd35b" - dependencies: - glob "^7.1.2" - gulp-chmod "^2.0.0" - gulp-filter "^5.0.1" - gulp-gunzip "1.0.0" - gulp-remote-src "^0.4.3" - gulp-symdest "^1.1.0" - gulp-untar "^0.0.6" - gulp-vinyl-zip "^2.1.0" - mocha "^4.0.1" - request "^2.83.0" - semver "^5.4.1" - source-map-support "^0.5.0" - url-parse "^1.1.9" - vinyl-source-stream "^1.1.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - -"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - -yauzl@^2.2.1: - version "2.9.1" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.9.1.tgz#a81981ea70a57946133883f029c5821a89359a7f" - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.0.1" - -yazl@^2.2.1: - version "2.4.3" - resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.4.3.tgz#ec26e5cc87d5601b9df8432dbdd3cd2e5173a071" - dependencies: - buffer-crc32 "~0.2.3" From a25a1cb188efdaddf4657b87f126a16c358b87cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Andr=C3=A9s=20Margffoy=20Tuay?= Date: Thu, 28 May 2020 17:52:01 -0500 Subject: [PATCH 04/10] git subrepo clone https://github.com/palantir/python-language-server.git external-deps/python-language-server/ subrepo: subdir: "external-deps/python-language-server" merged: "9b5cb2197" upstream: origin: "https://github.com/palantir/python-language-server.git" branch: "develop" commit: "9b5cb2197" git-subrepo: version: "0.4.1" origin: "https://github.com/ingydotnet/git-subrepo" commit: "a04d8c2" --- .../.circleci/config.yml | 60 + .../python-language-server/.coveragerc | 2 + .../python-language-server/.gitattributes | 1 + .../python-language-server/.gitignore | 114 ++ external-deps/python-language-server/.gitrepo | 12 + .../python-language-server/.pylintrc | 29 + external-deps/python-language-server/LICENSE | 21 + .../python-language-server/MANIFEST.in | 6 + .../python-language-server/README.rst | 165 ++ .../python-language-server/RELEASE.md | 11 + .../python-language-server/appveyor.yml | 32 + .../python-language-server/pyls/__init__.py | 19 + .../python-language-server/pyls/__main__.py | 127 ++ .../python-language-server/pyls/_utils.py | 215 ++ .../python-language-server/pyls/_version.py | 520 +++++ .../pyls/config/__init__.py | 1 + .../pyls/config/config.py | 155 ++ .../pyls/config/flake8_conf.py | 48 + .../pyls/config/pycodestyle_conf.py | 31 + .../pyls/config/source.py | 86 + .../python-language-server/pyls/hookspecs.py | 122 ++ .../python-language-server/pyls/lsp.py | 85 + .../pyls/plugins/__init__.py | 1 + .../pyls/plugins/autopep8_format.py | 64 + .../pyls/plugins/definition.py | 35 + .../pyls/plugins/flake8_lint.py | 154 ++ .../pyls/plugins/folding.py | 203 ++ .../pyls/plugins/highlight.py | 25 + .../pyls/plugins/hover.py | 48 + .../pyls/plugins/jedi_completion.py | 204 ++ .../pyls/plugins/jedi_rename.py | 48 + .../pyls/plugins/mccabe_lint.py | 40 + .../pyls/plugins/preload_imports.py | 34 + .../pyls/plugins/pycodestyle_lint.py | 81 + .../pyls/plugins/pydocstyle_lint.py | 119 ++ .../pyls/plugins/pyflakes_lint.py | 80 + .../pyls/plugins/pylint_lint.py | 165 ++ .../pyls/plugins/references.py | 24 + .../pyls/plugins/rope_completion.py | 107 + .../pyls/plugins/rope_rename.py | 54 + .../pyls/plugins/signature.py | 58 + .../pyls/plugins/symbols.py | 103 + .../pyls/plugins/yapf_format.py | 56 + .../python-language-server/pyls/python_ls.py | 435 ++++ .../python-language-server/pyls/uris.py | 129 ++ .../python-language-server/pyls/workspace.py | 264 +++ .../resources/auto-complete.gif | Bin 0 -> 55532 bytes .../resources/document-format.gif | Bin 0 -> 66169 bytes .../resources/document-symbols.gif | Bin 0 -> 37353 bytes .../resources/goto-definition.gif | Bin 0 -> 44400 bytes .../resources/hover.gif | Bin 0 -> 36464 bytes .../resources/linting.gif | Bin 0 -> 30013 bytes .../resources/references.gif | Bin 0 -> 109136 bytes .../resources/signature-help.gif | Bin 0 -> 10586 bytes .../scripts/circle/pypi.sh | 17 + .../python-language-server/setup.cfg | 18 + external-deps/python-language-server/setup.py | 104 + .../python-language-server/test/__init__.py | 11 + .../python-language-server/test/conftest.py | 11 + .../python-language-server/test/fixtures.py | 73 + .../test/plugins/__init__.py | 0 .../test/plugins/test_autopep8_format.py | 44 + .../test/plugins/test_completion.py | 337 +++ .../test/plugins/test_definitions.py | 57 + .../test/plugins/test_flake8_lint.py | 68 + .../test/plugins/test_folding.py | 168 ++ .../test/plugins/test_highlight.py | 56 + .../test/plugins/test_hover.py | 68 + .../test/plugins/test_jedi_rename.py | 48 + .../test/plugins/test_mccabe_lint.py | 37 + .../test/plugins/test_pycodestyle_lint.py | 112 + .../test/plugins/test_pydocstyle_lint.py | 56 + .../test/plugins/test_pyflakes_lint.py | 62 + .../test/plugins/test_pylint_lint.py | 118 ++ .../test/plugins/test_references.py | 80 + .../test/plugins/test_rope_rename.py | 42 + .../test/plugins/test_signature.py | 94 + .../test/plugins/test_symbols.py | 91 + .../test/plugins/test_yapf_format.py | 58 + .../test/test_document.py | 99 + .../test/test_language_server.py | 103 + .../python-language-server/test/test_uris.py | 50 + .../python-language-server/test/test_utils.py | 106 + .../test/test_workspace.py | 199 ++ .../python-language-server/versioneer.py | 1822 +++++++++++++++++ .../vscode-client/.gitignore | 4 + .../vscode-client/.vscodeignore | 9 + .../vscode-client/License.txt | 11 + .../vscode-client/README.md | 33 + .../vscode-client/ThirdPartyNotices.txt | 31 + .../vscode-client/package.json | 306 +++ .../vscode-client/src/extension.ts | 51 + .../vscode-client/tsconfig.json | 13 + .../vscode-client/yarn.lock | 1821 ++++++++++++++++ 94 files changed, 10881 insertions(+) create mode 100644 external-deps/python-language-server/.circleci/config.yml create mode 100644 external-deps/python-language-server/.coveragerc create mode 100644 external-deps/python-language-server/.gitattributes create mode 100644 external-deps/python-language-server/.gitignore create mode 100644 external-deps/python-language-server/.gitrepo create mode 100644 external-deps/python-language-server/.pylintrc create mode 100644 external-deps/python-language-server/LICENSE create mode 100644 external-deps/python-language-server/MANIFEST.in create mode 100644 external-deps/python-language-server/README.rst create mode 100644 external-deps/python-language-server/RELEASE.md create mode 100644 external-deps/python-language-server/appveyor.yml create mode 100644 external-deps/python-language-server/pyls/__init__.py create mode 100644 external-deps/python-language-server/pyls/__main__.py create mode 100644 external-deps/python-language-server/pyls/_utils.py create mode 100644 external-deps/python-language-server/pyls/_version.py create mode 100644 external-deps/python-language-server/pyls/config/__init__.py create mode 100644 external-deps/python-language-server/pyls/config/config.py create mode 100644 external-deps/python-language-server/pyls/config/flake8_conf.py create mode 100644 external-deps/python-language-server/pyls/config/pycodestyle_conf.py create mode 100644 external-deps/python-language-server/pyls/config/source.py create mode 100644 external-deps/python-language-server/pyls/hookspecs.py create mode 100644 external-deps/python-language-server/pyls/lsp.py create mode 100644 external-deps/python-language-server/pyls/plugins/__init__.py create mode 100644 external-deps/python-language-server/pyls/plugins/autopep8_format.py create mode 100644 external-deps/python-language-server/pyls/plugins/definition.py create mode 100644 external-deps/python-language-server/pyls/plugins/flake8_lint.py create mode 100644 external-deps/python-language-server/pyls/plugins/folding.py create mode 100644 external-deps/python-language-server/pyls/plugins/highlight.py create mode 100644 external-deps/python-language-server/pyls/plugins/hover.py create mode 100644 external-deps/python-language-server/pyls/plugins/jedi_completion.py create mode 100644 external-deps/python-language-server/pyls/plugins/jedi_rename.py create mode 100644 external-deps/python-language-server/pyls/plugins/mccabe_lint.py create mode 100644 external-deps/python-language-server/pyls/plugins/preload_imports.py create mode 100644 external-deps/python-language-server/pyls/plugins/pycodestyle_lint.py create mode 100644 external-deps/python-language-server/pyls/plugins/pydocstyle_lint.py create mode 100644 external-deps/python-language-server/pyls/plugins/pyflakes_lint.py create mode 100644 external-deps/python-language-server/pyls/plugins/pylint_lint.py create mode 100644 external-deps/python-language-server/pyls/plugins/references.py create mode 100644 external-deps/python-language-server/pyls/plugins/rope_completion.py create mode 100644 external-deps/python-language-server/pyls/plugins/rope_rename.py create mode 100644 external-deps/python-language-server/pyls/plugins/signature.py create mode 100644 external-deps/python-language-server/pyls/plugins/symbols.py create mode 100644 external-deps/python-language-server/pyls/plugins/yapf_format.py create mode 100644 external-deps/python-language-server/pyls/python_ls.py create mode 100644 external-deps/python-language-server/pyls/uris.py create mode 100644 external-deps/python-language-server/pyls/workspace.py create mode 100644 external-deps/python-language-server/resources/auto-complete.gif create mode 100644 external-deps/python-language-server/resources/document-format.gif create mode 100644 external-deps/python-language-server/resources/document-symbols.gif create mode 100644 external-deps/python-language-server/resources/goto-definition.gif create mode 100644 external-deps/python-language-server/resources/hover.gif create mode 100644 external-deps/python-language-server/resources/linting.gif create mode 100644 external-deps/python-language-server/resources/references.gif create mode 100644 external-deps/python-language-server/resources/signature-help.gif create mode 100755 external-deps/python-language-server/scripts/circle/pypi.sh create mode 100644 external-deps/python-language-server/setup.cfg create mode 100755 external-deps/python-language-server/setup.py create mode 100644 external-deps/python-language-server/test/__init__.py create mode 100644 external-deps/python-language-server/test/conftest.py create mode 100644 external-deps/python-language-server/test/fixtures.py create mode 100644 external-deps/python-language-server/test/plugins/__init__.py create mode 100644 external-deps/python-language-server/test/plugins/test_autopep8_format.py create mode 100644 external-deps/python-language-server/test/plugins/test_completion.py create mode 100644 external-deps/python-language-server/test/plugins/test_definitions.py create mode 100644 external-deps/python-language-server/test/plugins/test_flake8_lint.py create mode 100644 external-deps/python-language-server/test/plugins/test_folding.py create mode 100644 external-deps/python-language-server/test/plugins/test_highlight.py create mode 100644 external-deps/python-language-server/test/plugins/test_hover.py create mode 100644 external-deps/python-language-server/test/plugins/test_jedi_rename.py create mode 100644 external-deps/python-language-server/test/plugins/test_mccabe_lint.py create mode 100644 external-deps/python-language-server/test/plugins/test_pycodestyle_lint.py create mode 100644 external-deps/python-language-server/test/plugins/test_pydocstyle_lint.py create mode 100644 external-deps/python-language-server/test/plugins/test_pyflakes_lint.py create mode 100644 external-deps/python-language-server/test/plugins/test_pylint_lint.py create mode 100644 external-deps/python-language-server/test/plugins/test_references.py create mode 100644 external-deps/python-language-server/test/plugins/test_rope_rename.py create mode 100644 external-deps/python-language-server/test/plugins/test_signature.py create mode 100644 external-deps/python-language-server/test/plugins/test_symbols.py create mode 100644 external-deps/python-language-server/test/plugins/test_yapf_format.py create mode 100644 external-deps/python-language-server/test/test_document.py create mode 100644 external-deps/python-language-server/test/test_language_server.py create mode 100644 external-deps/python-language-server/test/test_uris.py create mode 100644 external-deps/python-language-server/test/test_utils.py create mode 100644 external-deps/python-language-server/test/test_workspace.py create mode 100644 external-deps/python-language-server/versioneer.py create mode 100644 external-deps/python-language-server/vscode-client/.gitignore create mode 100644 external-deps/python-language-server/vscode-client/.vscodeignore create mode 100644 external-deps/python-language-server/vscode-client/License.txt create mode 100644 external-deps/python-language-server/vscode-client/README.md create mode 100644 external-deps/python-language-server/vscode-client/ThirdPartyNotices.txt create mode 100644 external-deps/python-language-server/vscode-client/package.json create mode 100644 external-deps/python-language-server/vscode-client/src/extension.ts create mode 100644 external-deps/python-language-server/vscode-client/tsconfig.json create mode 100644 external-deps/python-language-server/vscode-client/yarn.lock diff --git a/external-deps/python-language-server/.circleci/config.yml b/external-deps/python-language-server/.circleci/config.yml new file mode 100644 index 00000000000..4beef059a47 --- /dev/null +++ b/external-deps/python-language-server/.circleci/config.yml @@ -0,0 +1,60 @@ +version: 2 + +jobs: + python2-test: + docker: + - image: "python:2.7-stretch" + steps: + - checkout + - run: pip install -e .[all] .[test] + - run: py.test -v test/ + - run: pylint pyls test + - run: pycodestyle pyls test + - run: pyflakes pyls test + + python3-test: + docker: + - image: "python:3.6-stretch" + steps: + - checkout + # To test Jedi environments + - run: python3 -m venv /tmp/pyenv + - run: /tmp/pyenv/bin/python -m pip install loghub + - run: pip install -e .[all] .[test] + - run: py.test -v test/ + + lint: + docker: + - image: "python:2.7-stretch" + steps: + - checkout + - run: pip install -e .[all] .[test] + - run: pylint pyls test + - run: pycodestyle pyls test + - run: pyflakes pyls test + + publish: + docker: + - image: "python:3.6-stretch" + steps: + - checkout + - run: ./scripts/circle/pypi.sh + + +workflows: + version: 2 + build: + jobs: + - python2-test: + filters: { tags: { only: /.*/ } } + - python3-test: + filters: { tags: { only: /.*/ } } + - publish: + filters: + tags: + only: /[0-9]+(\.[0-9]+)+((-(beta|rc)[0-9]{1,2})(\.[0-9])?)?/ + branches: + ignore: /.*/ + requires: + - python2-test + - python3-test diff --git a/external-deps/python-language-server/.coveragerc b/external-deps/python-language-server/.coveragerc new file mode 100644 index 00000000000..ba07147bd48 --- /dev/null +++ b/external-deps/python-language-server/.coveragerc @@ -0,0 +1,2 @@ +[run] +omit = pyls/_version.py diff --git a/external-deps/python-language-server/.gitattributes b/external-deps/python-language-server/.gitattributes new file mode 100644 index 00000000000..1602f1535a5 --- /dev/null +++ b/external-deps/python-language-server/.gitattributes @@ -0,0 +1 @@ +pyls/_version.py export-subst diff --git a/external-deps/python-language-server/.gitignore b/external-deps/python-language-server/.gitignore new file mode 100644 index 00000000000..ac609b32350 --- /dev/null +++ b/external-deps/python-language-server/.gitignore @@ -0,0 +1,114 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# IntelliJ +*.iml +*.ipr +*.iws +.idea/ +out/ + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +env3/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ +pytest.xml +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# IPython Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# dotenv +.env + +# virtualenv +venv/ +ENV/ + +# Spyder project settings +.spyderproject + +# Rope project settings +.ropeproject + +# JavaScript +**/*.vscode/ + +# vim +*.sw[mnopqrs] + +# Idea +.idea/ + +# Merge orig files +*.orig + +# Special files +.DS_Store diff --git a/external-deps/python-language-server/.gitrepo b/external-deps/python-language-server/.gitrepo new file mode 100644 index 00000000000..fd7d1946dd4 --- /dev/null +++ b/external-deps/python-language-server/.gitrepo @@ -0,0 +1,12 @@ +; DO NOT EDIT (unless you know what you are doing) +; +; This subdirectory is a git "subrepo", and this file is maintained by the +; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme +; +[subrepo] + remote = https://github.com/palantir/python-language-server.git + branch = develop + commit = 9b5cb2197405b2290161deb2abd8e2b139a53691 + parent = dbb0398cd7e309e6de7a7740c57a03ecbb26ac11 + method = merge + cmdver = 0.4.1 diff --git a/external-deps/python-language-server/.pylintrc b/external-deps/python-language-server/.pylintrc new file mode 100644 index 00000000000..29802a2cb6b --- /dev/null +++ b/external-deps/python-language-server/.pylintrc @@ -0,0 +1,29 @@ +[FORMAT] + +max-line-length = 120 + +[MESSAGES CONTROL] + +enable = + useless-suppression + +disable = + duplicate-code, + invalid-name, + fixme, + missing-docstring, + protected-access, + too-few-public-methods, + too-many-arguments, + too-many-instance-attributes, + import-error + +[REPORTS] + +reports = no + +[TYPECHECK] + +generated-members = + pyls_* + cache_clear diff --git a/external-deps/python-language-server/LICENSE b/external-deps/python-language-server/LICENSE new file mode 100644 index 00000000000..56c842e2625 --- /dev/null +++ b/external-deps/python-language-server/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright 2017 Palantir Technologies, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/external-deps/python-language-server/MANIFEST.in b/external-deps/python-language-server/MANIFEST.in new file mode 100644 index 00000000000..20438d9a329 --- /dev/null +++ b/external-deps/python-language-server/MANIFEST.in @@ -0,0 +1,6 @@ +include README.rst +include versioneer.py +include pyls/_version.py +include LICENSE +include .pylintrc +recursive-include test *.py diff --git a/external-deps/python-language-server/README.rst b/external-deps/python-language-server/README.rst new file mode 100644 index 00000000000..166391cea89 --- /dev/null +++ b/external-deps/python-language-server/README.rst @@ -0,0 +1,165 @@ +Python Language Server +====================== + +.. image:: https://circleci.com/gh/palantir/python-language-server.svg?style=shield + :target: https://circleci.com/gh/palantir/python-language-server + +.. image:: https://ci.appveyor.com/api/projects/status/mdacv6fnif7wonl0?svg=true + :target: https://ci.appveyor.com/project/gatesn/python-language-server + +.. image:: https://img.shields.io/github/license/palantir/python-language-server.svg + :target: https://github.com/palantir/python-language-server/blob/master/LICENSE + +A Python 2.7 and 3.5+ implementation of the `Language Server Protocol`_. + +Installation +------------ + +The base language server requires Jedi_ to provide Completions, Definitions, Hover, References, Signature Help, and +Symbols: + +``pip install python-language-server`` + +If the respective dependencies are found, the following optional providers will be enabled: + +* Rope_ for Completions and renaming +* Pyflakes_ linter to detect various errors +* McCabe_ linter for complexity checking +* pycodestyle_ linter for style checking +* pydocstyle_ linter for docstring style checking (disabled by default) +* autopep8_ for code formatting +* YAPF_ for code formatting (preferred over autopep8) + +Optional providers can be installed using the `extras` syntax. To install YAPF_ formatting for example: + +``pip install 'python-language-server[yapf]'`` + +All optional providers can be installed using: + +``pip install 'python-language-server[all]'`` + +If you get an error similar to ``'install_requires' must be a string or list of strings`` then please upgrade setuptools before trying again. + +``pip install -U setuptools`` + +3rd Party Plugins +~~~~~~~~~~~~~~~~~ +Installing these plugins will add extra functionality to the language server: + +* pyls-mypy_ Mypy type checking for Python 3 +* pyls-isort_ Isort import sort code formatting +* pyls-black_ for code formatting using Black_ + +Please see the above repositories for examples on how to write plugins for the Python Language Server. Please file an +issue if you require assistance writing a plugin. + +Configuration +------------- + +Configuration is loaded from zero or more configuration sources. Currently implemented are: + +* pycodestyle: discovered in ~/.config/pycodestyle, setup.cfg, tox.ini and pycodestyle.cfg. +* flake8: discovered in ~/.config/flake8, setup.cfg, tox.ini and flake8.cfg + +The default configuration source is pycodestyle. Change the `pyls.configurationSources` setting to `['flake8']` in +order to respect flake8 configuration instead. + +Overall configuration is computed first from user configuration (in home directory), overridden by configuration +passed in by the language client, and then overriden by configuration discovered in the workspace. + +To enable pydocstyle for linting docstrings add the following setting in your LSP configuration: +``` +"pyls.plugins.pydocstyle.enabled": true +``` + +See `vscode-client/package.json`_ for the full set of supported configuration options. + +.. _vscode-client/package.json: vscode-client/package.json + +Language Server Features +------------------------ + +Auto Completion: + +.. image:: https://raw.githubusercontent.com/palantir/python-language-server/develop/resources/auto-complete.gif + +Code Linting with pycodestyle and pyflakes: + +.. image:: https://raw.githubusercontent.com/palantir/python-language-server/develop/resources/linting.gif + +Signature Help: + +.. image:: https://raw.githubusercontent.com/palantir/python-language-server/develop/resources/signature-help.gif + +Go to definition: + +.. image:: https://raw.githubusercontent.com/palantir/python-language-server/develop/resources/goto-definition.gif + +Hover: + +.. image:: https://raw.githubusercontent.com/palantir/python-language-server/develop/resources/hover.gif + +Find References: + +.. image:: https://raw.githubusercontent.com/palantir/python-language-server/develop/resources/references.gif + +Document Symbols: + +.. image:: https://raw.githubusercontent.com/palantir/python-language-server/develop/resources/document-symbols.gif + +Document Formatting: + +.. image:: https://raw.githubusercontent.com/palantir/python-language-server/develop/resources/document-format.gif + +Development +----------- + +To run the test suite: + +``pip install .[test] && pytest`` + +Develop against VS Code +======================= + +The Python language server can be developed against a local instance of Visual Studio Code. + +Install `VSCode `_ + +.. code-block:: bash + + # Setup a virtual env + virtualenv env + . env/bin/activate + + # Install pyls + pip install . + + # Install the vscode-client extension + cd vscode-client + yarn install + + # Run VSCode which is configured to use pyls + # See the bottom of vscode-client/src/extension.ts for info + yarn run vscode -- $PWD/../ + +Then to debug, click View -> Output and in the dropdown will be pyls. +To refresh VSCode, press `Cmd + r` + +License +------- + +This project is made available under the MIT License. + +.. _Language Server Protocol: https://github.com/Microsoft/language-server-protocol +.. _Jedi: https://github.com/davidhalter/jedi +.. _Rope: https://github.com/python-rope/rope +.. _Pyflakes: https://github.com/PyCQA/pyflakes +.. _McCabe: https://github.com/PyCQA/mccabe +.. _pycodestyle: https://github.com/PyCQA/pycodestyle +.. _pydocstyle: https://github.com/PyCQA/pydocstyle +.. _YAPF: https://github.com/google/yapf +.. _autopep8: https://github.com/hhatto/autopep8 +.. _pyls-mypy: https://github.com/tomv564/pyls-mypy +.. _pyls-isort: https://github.com/paradoxxxzero/pyls-isort +.. _pyls-black: https://github.com/rupert/pyls-black +.. _Black: https://github.com/ambv/black diff --git a/external-deps/python-language-server/RELEASE.md b/external-deps/python-language-server/RELEASE.md new file mode 100644 index 00000000000..2311c1b084c --- /dev/null +++ b/external-deps/python-language-server/RELEASE.md @@ -0,0 +1,11 @@ +To release a new version of the PyLS you need to follow these steps: + +* Close the current milestone on Github + +* git pull or git fetch/merge + +* git tag -a X.X.X -m 'Release X.X.X' + +* git push upstream --tags + +* Publish release in our Github Releases page diff --git a/external-deps/python-language-server/appveyor.yml b/external-deps/python-language-server/appveyor.yml new file mode 100644 index 00000000000..4950b8aba0e --- /dev/null +++ b/external-deps/python-language-server/appveyor.yml @@ -0,0 +1,32 @@ +environment: + global: + APPVEYOR_RDP_PASSWORD: "dcca4c4863E30d56c2e0dda6327370b3#" + matrix: + - PYTHON: "C:\\Python27" + PYTHON_VERSION: "2.7.15" + PYTHON_ARCH: "64" + + - PYTHON: "C:\\Python36" + PYTHON_VERSION: "3.6.8" + PYTHON_ARCH: "64" + +matrix: + fast_finish: true + +init: + - "ECHO %PYTHON% %PYTHON_VERSION% %PYTHON_ARCH%" + +install: + - "%PYTHON%/python.exe -m pip install --upgrade pip setuptools" + - "%PYTHON%/python.exe -m pip install .[all] .[test]" + +test_script: + - "%PYTHON%/Scripts/pytest.exe -v test/" + +# on_finish: +# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + +build: false # Not a C# project + +cache: + - '%APPDATA%\pip\Cache' diff --git a/external-deps/python-language-server/pyls/__init__.py b/external-deps/python-language-server/pyls/__init__.py new file mode 100644 index 00000000000..d3e7ead0fc1 --- /dev/null +++ b/external-deps/python-language-server/pyls/__init__.py @@ -0,0 +1,19 @@ +# Copyright 2017 Palantir Technologies, Inc. +import os +import sys +import pluggy +from ._version import get_versions + +if sys.version_info[0] < 3: + from future.standard_library import install_aliases + install_aliases() + +__version__ = get_versions()['version'] +del get_versions + +PYLS = 'pyls' + +hookspec = pluggy.HookspecMarker(PYLS) +hookimpl = pluggy.HookimplMarker(PYLS) + +IS_WIN = os.name == 'nt' diff --git a/external-deps/python-language-server/pyls/__main__.py b/external-deps/python-language-server/pyls/__main__.py new file mode 100644 index 00000000000..6440085f05f --- /dev/null +++ b/external-deps/python-language-server/pyls/__main__.py @@ -0,0 +1,127 @@ +# Copyright 2017 Palantir Technologies, Inc. +import argparse +import logging +import logging.config +import sys + +try: + import ujson as json +except Exception: # pylint: disable=broad-except + import json + +from .python_ls import (PythonLanguageServer, start_io_lang_server, + start_tcp_lang_server) + +LOG_FORMAT = "%(asctime)s UTC - %(levelname)s - %(name)s - %(message)s" + + +def add_arguments(parser): + parser.description = "Python Language Server" + + parser.add_argument( + "--tcp", action="store_true", + help="Use TCP server instead of stdio" + ) + parser.add_argument( + "--host", default="127.0.0.1", + help="Bind to this address" + ) + parser.add_argument( + "--port", type=int, default=2087, + help="Bind to this port" + ) + parser.add_argument( + '--check-parent-process', action="store_true", + help="Check whether parent process is still alive using os.kill(ppid, 0) " + "and auto shut down language server process when parent process is not alive." + "Note that this may not work on a Windows machine." + ) + + log_group = parser.add_mutually_exclusive_group() + log_group.add_argument( + "--log-config", + help="Path to a JSON file containing Python logging config." + ) + log_group.add_argument( + "--log-file", + help="Redirect logs to the given file instead of writing to stderr." + "Has no effect if used with --log-config." + ) + + parser.add_argument( + '-v', '--verbose', action='count', default=0, + help="Increase verbosity of log output, overrides log config file" + ) + + +def main(): + parser = argparse.ArgumentParser() + add_arguments(parser) + args = parser.parse_args() + _configure_logger(args.verbose, args.log_config, args.log_file) + + if args.tcp: + start_tcp_lang_server(args.host, args.port, args.check_parent_process, + PythonLanguageServer) + else: + stdin, stdout = _binary_stdio() + start_io_lang_server(stdin, stdout, args.check_parent_process, + PythonLanguageServer) + + +def _binary_stdio(): + """Construct binary stdio streams (not text mode). + + This seems to be different for Window/Unix Python2/3, so going by: + https://stackoverflow.com/questions/2850893/reading-binary-data-from-stdin + """ + PY3K = sys.version_info >= (3, 0) + + if PY3K: + # pylint: disable=no-member + stdin, stdout = sys.stdin.buffer, sys.stdout.buffer + else: + # Python 2 on Windows opens sys.stdin in text mode, and + # binary data that read from it becomes corrupted on \r\n + if sys.platform == "win32": + # set sys.stdin to binary mode + # pylint: disable=no-member,import-error + import os + import msvcrt + msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) + msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) + stdin, stdout = sys.stdin, sys.stdout + + return stdin, stdout + + +def _configure_logger(verbose=0, log_config=None, log_file=None): + root_logger = logging.root + + if log_config: + with open(log_config, 'r') as f: + logging.config.dictConfig(json.load(f)) + else: + formatter = logging.Formatter(LOG_FORMAT) + if log_file: + log_handler = logging.handlers.RotatingFileHandler( + log_file, mode='a', maxBytes=50*1024*1024, + backupCount=10, encoding=None, delay=0 + ) + else: + log_handler = logging.StreamHandler() + log_handler.setFormatter(formatter) + root_logger.addHandler(log_handler) + + if verbose == 0: + level = logging.WARNING + elif verbose == 1: + level = logging.INFO + elif verbose >= 2: + level = logging.DEBUG + + root_logger.setLevel(level) + + +if __name__ == '__main__': + main() diff --git a/external-deps/python-language-server/pyls/_utils.py b/external-deps/python-language-server/pyls/_utils.py new file mode 100644 index 00000000000..b1a3bd96c8d --- /dev/null +++ b/external-deps/python-language-server/pyls/_utils.py @@ -0,0 +1,215 @@ +# Copyright 2017 Palantir Technologies, Inc. +import functools +import inspect +import logging +import os +import sys +import threading + +import jedi + +PY2 = sys.version_info.major == 2 +JEDI_VERSION = jedi.__version__ + +if PY2: + import pathlib2 as pathlib +else: + import pathlib + +log = logging.getLogger(__name__) + + +def debounce(interval_s, keyed_by=None): + """Debounce calls to this function until interval_s seconds have passed.""" + def wrapper(func): + timers = {} + lock = threading.Lock() + + @functools.wraps(func) + def debounced(*args, **kwargs): + call_args = inspect.getcallargs(func, *args, **kwargs) + key = call_args[keyed_by] if keyed_by else None + + def run(): + with lock: + del timers[key] + return func(*args, **kwargs) + + with lock: + old_timer = timers.get(key) + if old_timer: + old_timer.cancel() + + timer = threading.Timer(interval_s, run) + timers[key] = timer + timer.start() + return debounced + return wrapper + + +def find_parents(root, path, names): + """Find files matching the given names relative to the given path. + + Args: + path (str): The file path to start searching up from. + names (List[str]): The file/directory names to look for. + root (str): The directory at which to stop recursing upwards. + + Note: + The path MUST be within the root. + """ + if not root: + return [] + + if not os.path.commonprefix((root, path)): + log.warning("Path %s not in %s", path, root) + return [] + + # Split the relative by directory, generate all the parent directories, then check each of them. + # This avoids running a loop that has different base-cases for unix/windows + # e.g. /a/b and /a/b/c/d/e.py -> ['/a/b', 'c', 'd'] + dirs = [root] + os.path.relpath(os.path.dirname(path), root).split(os.path.sep) + + # Search each of /a/b/c, /a/b, /a + while dirs: + search_dir = os.path.join(*dirs) + existing = list(filter(os.path.exists, [os.path.join(search_dir, n) for n in names])) + if existing: + return existing + dirs.pop() + + # Otherwise nothing + return [] + + +def match_uri_to_workspace(uri, workspaces): + if uri is None: + return None + max_len, chosen_workspace = -1, None + path = pathlib.Path(uri).parts + for workspace in workspaces: + try: + workspace_parts = pathlib.Path(workspace).parts + except TypeError: + # This can happen in Python2 if 'value' is a subclass of string + workspace_parts = pathlib.Path(unicode(workspace)).parts + if len(workspace_parts) > len(path): + continue + match_len = 0 + for workspace_part, path_part in zip(workspace_parts, path): + if workspace_part == path_part: + match_len += 1 + if match_len > 0: + if match_len > max_len: + max_len = match_len + chosen_workspace = workspace + return chosen_workspace + + +def list_to_string(value): + return ",".join(value) if isinstance(value, list) else value + + +def merge_dicts(dict_a, dict_b): + """Recursively merge dictionary b into dictionary a. + + If override_nones is True, then + """ + def _merge_dicts_(a, b): + for key in set(a.keys()).union(b.keys()): + if key in a and key in b: + if isinstance(a[key], dict) and isinstance(b[key], dict): + yield (key, dict(_merge_dicts_(a[key], b[key]))) + elif b[key] is not None: + yield (key, b[key]) + else: + yield (key, a[key]) + elif key in a: + yield (key, a[key]) + elif b[key] is not None: + yield (key, b[key]) + 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. + """ + contents = contents.replace('\t', u'\u00A0' * 4) + contents = contents.replace(' ', u'\u00A0' * 2) + return contents + + +def clip_column(column, lines, line_number): + """ + 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 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, + 'column': clip_column(position['character'], + document.lines, + position['line'])} + return code_position + + +if os.name == 'nt': + import ctypes + + kernel32 = ctypes.windll.kernel32 + PROCESS_QUERY_INFROMATION = 0x1000 + + def is_process_alive(pid): + """Check whether the process with the given pid is still alive. + + Running `os.kill()` on Windows always exits the process, so it can't be used to check for an alive process. + see: https://docs.python.org/3/library/os.html?highlight=os%20kill#os.kill + + Hence ctypes is used to check for the process directly via windows API avoiding any other 3rd-party dependency. + + Args: + pid (int): process ID + + Returns: + bool: False if the process is not alive or don't have permission to check, True otherwise. + """ + process = kernel32.OpenProcess(PROCESS_QUERY_INFROMATION, 0, pid) + if process != 0: + kernel32.CloseHandle(process) + return True + return False + +else: + import errno + + def is_process_alive(pid): + """Check whether the process with the given pid is still alive. + + Args: + pid (int): process ID + + Returns: + bool: False if the process is not alive or don't have permission to check, True otherwise. + """ + if pid < 0: + return False + try: + os.kill(pid, 0) + except OSError as e: + return e.errno == errno.EPERM + else: + return True diff --git a/external-deps/python-language-server/pyls/_version.py b/external-deps/python-language-server/pyls/_version.py new file mode 100644 index 00000000000..aab9f7954eb --- /dev/null +++ b/external-deps/python-language-server/pyls/_version.py @@ -0,0 +1,520 @@ +# pylint: skip-file +# This file helps to compute a version number in source trees obtained from +# git-archive tarball (such as those provided by githubs download-from-tag +# feature). Distribution tarballs (built by setup.py sdist) and build +# directories (produced by setup.py build) will contain a much shorter file +# that just contains the computed version number. + +# This file is released into the public domain. Generated by +# versioneer-0.18 (https://github.com/warner/python-versioneer) + +"""Git implementation of _version.py.""" + +import errno +import os +import re +import subprocess +import sys + + +def get_keywords(): + """Get the keywords needed to look up the version information.""" + # these strings will be replaced by git during git-archive. + # setup.py/versioneer.py will grep for the variable names, so they must + # each be defined on a line of their own. _version.py will just call + # get_keywords(). + git_refnames = "$Format:%d$" + git_full = "$Format:%H$" + git_date = "$Format:%ci$" + keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} + return keywords + + +class VersioneerConfig: + """Container for Versioneer configuration parameters.""" + + +def get_config(): + """Create, populate and return the VersioneerConfig() object.""" + # these strings are filled in when 'setup.py versioneer' creates + # _version.py + cfg = VersioneerConfig() + cfg.VCS = "git" + cfg.style = "pep440" + cfg.tag_prefix = "" + cfg.parentdir_prefix = "" + cfg.versionfile_source = "pyls/_version.py" + cfg.verbose = False + return cfg + + +class NotThisMethod(Exception): + """Exception raised if a method is not valid for the current scenario.""" + + +LONG_VERSION_PY = {} +HANDLERS = {} + + +def register_vcs_handler(vcs, method): # decorator + """Decorator to mark a method as the handler for a particular VCS.""" + def decorate(f): + """Store f in HANDLERS[vcs][method].""" + if vcs not in HANDLERS: + HANDLERS[vcs] = {} + HANDLERS[vcs][method] = f + return f + return decorate + + +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, + env=None): + """Call the given command(s).""" + assert isinstance(commands, list) + p = None + for c in commands: + try: + dispcmd = str([c] + args) + # remember shell=False, so use git.cmd on windows, not just git + p = subprocess.Popen([c] + args, cwd=cwd, env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr + else None)) + break + except EnvironmentError: + e = sys.exc_info()[1] + if e.errno == errno.ENOENT: + continue + if verbose: + print("unable to run %s" % dispcmd) + print(e) + return None, None + else: + if verbose: + print("unable to find command, tried %s" % (commands,)) + return None, None + stdout = p.communicate()[0].strip() + if sys.version_info[0] >= 3: + stdout = stdout.decode() + if p.returncode != 0: + if verbose: + print("unable to run %s (error)" % dispcmd) + print("stdout was %s" % stdout) + return None, p.returncode + return stdout, p.returncode + + +def versions_from_parentdir(parentdir_prefix, root, verbose): + """Try to determine the version from the parent directory name. + + Source tarballs conventionally unpack into a directory that includes both + the project name and a version string. We will also support searching up + two directory levels for an appropriately named parent directory + """ + rootdirs = [] + + for i in range(3): + dirname = os.path.basename(root) + if dirname.startswith(parentdir_prefix): + return {"version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, "error": None, "date": None} + else: + rootdirs.append(root) + root = os.path.dirname(root) # up a level + + if verbose: + print("Tried directories %s but none started with prefix %s" % + (str(rootdirs), parentdir_prefix)) + raise NotThisMethod("rootdir doesn't start with parentdir_prefix") + + +@register_vcs_handler("git", "get_keywords") +def git_get_keywords(versionfile_abs): + """Extract version information from the given file.""" + # the code embedded in _version.py can just fetch the value of these + # keywords. When used from setup.py, we don't want to import _version.py, + # so we do it with a regexp instead. This function is not used from + # _version.py. + keywords = {} + try: + f = open(versionfile_abs, "r") + for line in f.readlines(): + if line.strip().startswith("git_refnames ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["refnames"] = mo.group(1) + if line.strip().startswith("git_full ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["full"] = mo.group(1) + if line.strip().startswith("git_date ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["date"] = mo.group(1) + f.close() + except EnvironmentError: + pass + return keywords + + +@register_vcs_handler("git", "keywords") +def git_versions_from_keywords(keywords, tag_prefix, verbose): + """Get version information from git keywords.""" + if not keywords: + raise NotThisMethod("no keywords at all, weird") + date = keywords.get("date") + if date is not None: + # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant + # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 + # -like" string, which we must then edit to make compliant), because + # it's been around since git-1.5.3, and it's too difficult to + # discover which version we're using, or to work around using an + # older one. + date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) + refnames = keywords["refnames"].strip() + if refnames.startswith("$Format"): + if verbose: + print("keywords are unexpanded, not using") + raise NotThisMethod("unexpanded keywords, not a git-archive tarball") + refs = set([r.strip() for r in refnames.strip("()").split(",")]) + # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of + # just "foo-1.0". If we see a "tag: " prefix, prefer those. + TAG = "tag: " + tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + if not tags: + # Either we're using git < 1.8.3, or there really are no tags. We use + # a heuristic: assume all version tags have a digit. The old git %d + # expansion behaves like git log --decorate=short and strips out the + # refs/heads/ and refs/tags/ prefixes that would let us distinguish + # between branches and tags. By ignoring refnames without digits, we + # filter out many common branch names like "release" and + # "stabilization", as well as "HEAD" and "master". + tags = set([r for r in refs if re.search(r'\d', r)]) + if verbose: + print("discarding '%s', no digits" % ",".join(refs - tags)) + if verbose: + print("likely tags: %s" % ",".join(sorted(tags))) + for ref in sorted(tags): + # sorting will prefer e.g. "2.0" over "2.0rc1" + if ref.startswith(tag_prefix): + r = ref[len(tag_prefix):] + if verbose: + print("picking %s" % r) + return {"version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": None, + "date": date} + # no suitable tags, so version is "0+unknown", but full hex is still there + if verbose: + print("no suitable tags, using unknown + full revision id") + return {"version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": "no suitable tags", "date": None} + + +@register_vcs_handler("git", "pieces_from_vcs") +def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): + """Get version from 'git describe' in the root of the source tree. + + This only gets called if the git-archive 'subst' keywords were *not* + expanded, and _version.py hasn't already been rewritten with a short + version string, meaning we're inside a checked out source tree. + """ + GITS = ["git"] + if sys.platform == "win32": + GITS = ["git.cmd", "git.exe"] + + out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, + hide_stderr=True) + if rc != 0: + if verbose: + print("Directory %s not under git control" % root) + raise NotThisMethod("'git rev-parse --git-dir' returned error") + + # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] + # if there isn't one, this yields HEX[-dirty] (no NUM) + describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", + "--always", "--long", + "--match", "%s*" % tag_prefix], + cwd=root) + # --long was added in git-1.5.5 + if describe_out is None: + raise NotThisMethod("'git describe' failed") + describe_out = describe_out.strip() + full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) + if full_out is None: + raise NotThisMethod("'git rev-parse' failed") + full_out = full_out.strip() + + pieces = {} + pieces["long"] = full_out + pieces["short"] = full_out[:7] # maybe improved later + pieces["error"] = None + + # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] + # TAG might have hyphens. + git_describe = describe_out + + # look for -dirty suffix + dirty = git_describe.endswith("-dirty") + pieces["dirty"] = dirty + if dirty: + git_describe = git_describe[:git_describe.rindex("-dirty")] + + # now we have TAG-NUM-gHEX or HEX + + if "-" in git_describe: + # TAG-NUM-gHEX + mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + if not mo: + # unparseable. Maybe git-describe is misbehaving? + pieces["error"] = ("unable to parse git-describe output: '%s'" + % describe_out) + return pieces + + # tag + full_tag = mo.group(1) + if not full_tag.startswith(tag_prefix): + if verbose: + fmt = "tag '%s' doesn't start with prefix '%s'" + print(fmt % (full_tag, tag_prefix)) + pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" + % (full_tag, tag_prefix)) + return pieces + pieces["closest-tag"] = full_tag[len(tag_prefix):] + + # distance: number of commits since tag + pieces["distance"] = int(mo.group(2)) + + # commit: short hex revision ID + pieces["short"] = mo.group(3) + + else: + # HEX: no tags + pieces["closest-tag"] = None + count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], + cwd=root) + pieces["distance"] = int(count_out) # total number of commits + + # commit date: see ISO-8601 comment in git_versions_from_keywords() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], + cwd=root)[0].strip() + pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) + + return pieces + + +def plus_or_dot(pieces): + """Return a + if we don't already have one, else return a .""" + if "+" in pieces.get("closest-tag", ""): + return "." + return "+" + + +def render_pep440(pieces): + """Build up version string, with post-release "local version identifier". + + Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you + get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty + + Exceptions: + 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += plus_or_dot(pieces) + rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + else: + # exception #1 + rendered = "0+untagged.%d.g%s" % (pieces["distance"], + pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + return rendered + + +def render_pep440_pre(pieces): + """TAG[.post.devDISTANCE] -- No -dirty. + + Exceptions: + 1: no tags. 0.post.devDISTANCE + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"]: + rendered += ".post.dev%d" % pieces["distance"] + else: + # exception #1 + rendered = "0.post.dev%d" % pieces["distance"] + return rendered + + +def render_pep440_post(pieces): + """TAG[.postDISTANCE[.dev0]+gHEX] . + + The ".dev0" means dirty. Note that .dev0 sorts backwards + (a dirty tree will appear "older" than the corresponding clean one), + but you shouldn't be releasing software with -dirty anyways. + + Exceptions: + 1: no tags. 0.postDISTANCE[.dev0] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += ".post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + rendered += plus_or_dot(pieces) + rendered += "g%s" % pieces["short"] + else: + # exception #1 + rendered = "0.post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + rendered += "+g%s" % pieces["short"] + return rendered + + +def render_pep440_old(pieces): + """TAG[.postDISTANCE[.dev0]] . + + The ".dev0" means dirty. + + Eexceptions: + 1: no tags. 0.postDISTANCE[.dev0] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += ".post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + else: + # exception #1 + rendered = "0.post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + return rendered + + +def render_git_describe(pieces): + """TAG[-DISTANCE-gHEX][-dirty]. + + Like 'git describe --tags --dirty --always'. + + Exceptions: + 1: no tags. HEX[-dirty] (note: no 'g' prefix) + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"]: + rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) + else: + # exception #1 + rendered = pieces["short"] + if pieces["dirty"]: + rendered += "-dirty" + return rendered + + +def render_git_describe_long(pieces): + """TAG-DISTANCE-gHEX[-dirty]. + + Like 'git describe --tags --dirty --always -long'. + The distance/hash is unconditional. + + Exceptions: + 1: no tags. HEX[-dirty] (note: no 'g' prefix) + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) + else: + # exception #1 + rendered = pieces["short"] + if pieces["dirty"]: + rendered += "-dirty" + return rendered + + +def render(pieces, style): + """Render the given version pieces into the requested style.""" + if pieces["error"]: + return {"version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None} + + if not style or style == "default": + style = "pep440" # the default + + if style == "pep440": + rendered = render_pep440(pieces) + elif style == "pep440-pre": + rendered = render_pep440_pre(pieces) + elif style == "pep440-post": + rendered = render_pep440_post(pieces) + elif style == "pep440-old": + rendered = render_pep440_old(pieces) + elif style == "git-describe": + rendered = render_git_describe(pieces) + elif style == "git-describe-long": + rendered = render_git_describe_long(pieces) + else: + raise ValueError("unknown style '%s'" % style) + + return {"version": rendered, "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], "error": None, + "date": pieces.get("date")} + + +def get_versions(): + """Get version information or return default if unable to do so.""" + # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have + # __file__, we can work backwards from there to the root. Some + # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which + # case we can only use expanded keywords. + + cfg = get_config() + verbose = cfg.verbose + + try: + return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, + verbose) + except NotThisMethod: + pass + + try: + root = os.path.realpath(__file__) + # versionfile_source is the relative path from the top of the source + # tree (where the .git directory might live) to this file. Invert + # this to find the root from __file__. + for i in cfg.versionfile_source.split('/'): + root = os.path.dirname(root) + except NameError: + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to find root of source tree", + "date": None} + + try: + pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) + return render(pieces, cfg.style) + except NotThisMethod: + pass + + try: + if cfg.parentdir_prefix: + return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) + except NotThisMethod: + pass + + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", "date": None} diff --git a/external-deps/python-language-server/pyls/config/__init__.py b/external-deps/python-language-server/pyls/config/__init__.py new file mode 100644 index 00000000000..9c6eb52c2ac --- /dev/null +++ b/external-deps/python-language-server/pyls/config/__init__.py @@ -0,0 +1 @@ +# Copyright 2017 Palantir Technologies, Inc. diff --git a/external-deps/python-language-server/pyls/config/config.py b/external-deps/python-language-server/pyls/config/config.py new file mode 100644 index 00000000000..65696d8179b --- /dev/null +++ b/external-deps/python-language-server/pyls/config/config.py @@ -0,0 +1,155 @@ +# Copyright 2017 Palantir Technologies, Inc. +import logging +import pkg_resources +try: + from functools import lru_cache +except ImportError: + from backports.functools_lru_cache import lru_cache + +import pluggy + +from pyls import _utils, hookspecs, uris, PYLS + +log = logging.getLogger(__name__) + +# Sources of config, first source overrides next source +DEFAULT_CONFIG_SOURCES = ['pycodestyle'] + + +class Config(object): + + def __init__(self, root_uri, init_opts, process_id, capabilities): + self._root_path = uris.to_fs_path(root_uri) + self._root_uri = root_uri + self._init_opts = init_opts + self._process_id = process_id + self._capabilities = capabilities + + self._settings = {} + self._plugin_settings = {} + + self._config_sources = {} + try: + from .flake8_conf import Flake8Config + self._config_sources['flake8'] = Flake8Config(self._root_path) + except ImportError: + pass + try: + from .pycodestyle_conf import PyCodeStyleConfig + self._config_sources['pycodestyle'] = PyCodeStyleConfig(self._root_path) + except ImportError: + pass + + self._pm = pluggy.PluginManager(PYLS) + self._pm.trace.root.setwriter(log.debug) + self._pm.enable_tracing() + self._pm.add_hookspecs(hookspecs) + + # Pluggy will skip loading a plugin if it throws a DistributionNotFound exception. + # However I don't want all plugins to have to catch ImportError and re-throw. So here we'll filter + # out any entry points that throw ImportError assuming one or more of their dependencies isn't present. + for entry_point in pkg_resources.iter_entry_points(PYLS): + try: + entry_point.load() + except ImportError as e: + log.warning("Failed to load %s entry point '%s': %s", PYLS, entry_point.name, e) + self._pm.set_blocked(entry_point.name) + + # Load the entry points into pluggy, having blocked any failing ones + self._pm.load_setuptools_entrypoints(PYLS) + + for name, plugin in self._pm.list_name_plugin(): + if plugin is not None: + log.info("Loaded pyls plugin %s from %s", name, plugin) + + for plugin_conf in self._pm.hook.pyls_settings(config=self): + self._plugin_settings = _utils.merge_dicts(self._plugin_settings, plugin_conf) + + self._update_disabled_plugins() + + @property + def disabled_plugins(self): + return self._disabled_plugins + + @property + def plugin_manager(self): + return self._pm + + @property + def init_opts(self): + return self._init_opts + + @property + def root_uri(self): + return self._root_uri + + @property + def process_id(self): + return self._process_id + + @property + def capabilities(self): + return self._capabilities + + @lru_cache(maxsize=32) + def settings(self, document_path=None): + """Settings are constructed from a few sources: + + 1. User settings, found in user's home directory + 2. Plugin settings, reported by PyLS plugins + 3. LSP settings, given to us from didChangeConfiguration + 4. Project settings, found in config files in the current project. + + Since this function is nondeterministic, it is important to call + settings.cache_clear() when the config is updated + """ + settings = {} + sources = self._settings.get('configurationSources', DEFAULT_CONFIG_SOURCES) + + for source_name in reversed(sources): + source = self._config_sources.get(source_name) + if not source: + continue + source_conf = source.user_config() + log.debug("Got user config from %s: %s", source.__class__.__name__, source_conf) + settings = _utils.merge_dicts(settings, source_conf) + log.debug("With user configuration: %s", settings) + + settings = _utils.merge_dicts(settings, self._plugin_settings) + log.debug("With plugin configuration: %s", settings) + + settings = _utils.merge_dicts(settings, self._settings) + log.debug("With lsp configuration: %s", settings) + + for source_name in reversed(sources): + source = self._config_sources.get(source_name) + if not source: + continue + source_conf = source.project_config(document_path or self._root_path) + log.debug("Got project config from %s: %s", source.__class__.__name__, source_conf) + settings = _utils.merge_dicts(settings, source_conf) + log.debug("With project configuration: %s", settings) + + return settings + + def find_parents(self, path, names): + root_path = uris.to_fs_path(self._root_uri) + return _utils.find_parents(root_path, path, names) + + def plugin_settings(self, plugin, document_path=None): + return self.settings(document_path=document_path).get('plugins', {}).get(plugin, {}) + + def update(self, settings): + """Recursively merge the given settings into the current settings.""" + self.settings.cache_clear() + self._settings = settings + log.info("Updated settings to %s", self._settings) + self._update_disabled_plugins() + + def _update_disabled_plugins(self): + # All plugins default to enabled + self._disabled_plugins = [ + plugin for name, plugin in self.plugin_manager.list_name_plugin() + if not self.settings().get('plugins', {}).get(name, {}).get('enabled', True) + ] + log.info("Disabled plugins: %s", self._disabled_plugins) diff --git a/external-deps/python-language-server/pyls/config/flake8_conf.py b/external-deps/python-language-server/pyls/config/flake8_conf.py new file mode 100644 index 00000000000..47b6cfad734 --- /dev/null +++ b/external-deps/python-language-server/pyls/config/flake8_conf.py @@ -0,0 +1,48 @@ +# Copyright 2017 Palantir Technologies, Inc. +import logging +import os +from pyls._utils import find_parents +from .source import ConfigSource + +log = logging.getLogger(__name__) + +CONFIG_KEY = 'flake8' +PROJECT_CONFIGS = ['.flake8', 'setup.cfg', 'tox.ini'] + +OPTIONS = [ + # mccabe + ('max-complexity', 'plugins.mccabe.threshold', int), + # pycodestyle + ('exclude', 'plugins.pycodestyle.exclude', list), + ('filename', 'plugins.pycodestyle.filename', list), + ('hang-closing', 'plugins.pycodestyle.hangClosing', bool), + ('ignore', 'plugins.pycodestyle.ignore', list), + ('max-line-length', 'plugins.pycodestyle.maxLineLength', int), + ('select', 'plugins.pycodestyle.select', list), + # flake8 + ('exclude', 'plugins.flake8.exclude', list), + ('filename', 'plugins.flake8.filename', list), + ('hang-closing', 'plugins.flake8.hangClosing', bool), + ('ignore', 'plugins.flake8.ignore', list), + ('max-line-length', 'plugins.flake8.maxLineLength', int), + ('select', 'plugins.flake8.select', list), +] + + +class Flake8Config(ConfigSource): + """Parse flake8 configurations.""" + + def user_config(self): + config_file = self._user_config_file() + config = self.read_config_from_files([config_file]) + return self.parse_config(config, CONFIG_KEY, OPTIONS) + + def _user_config_file(self): + if self.is_windows: + return os.path.expanduser('~\\.flake8') + return os.path.join(self.xdg_home, 'flake8') + + def project_config(self, document_path): + files = find_parents(self.root_path, document_path, PROJECT_CONFIGS) + config = self.read_config_from_files(files) + return self.parse_config(config, CONFIG_KEY, OPTIONS) diff --git a/external-deps/python-language-server/pyls/config/pycodestyle_conf.py b/external-deps/python-language-server/pyls/config/pycodestyle_conf.py new file mode 100644 index 00000000000..49d3d16f6f9 --- /dev/null +++ b/external-deps/python-language-server/pyls/config/pycodestyle_conf.py @@ -0,0 +1,31 @@ +# Copyright 2017 Palantir Technologies, Inc. +import pycodestyle +from pyls._utils import find_parents +from .source import ConfigSource + + +CONFIG_KEY = 'pycodestyle' +USER_CONFIGS = [pycodestyle.USER_CONFIG] if pycodestyle.USER_CONFIG else [] +PROJECT_CONFIGS = ['pycodestyle.cfg', 'setup.cfg', 'tox.ini'] + +OPTIONS = [ + ('exclude', 'plugins.pycodestyle.exclude', list), + ('filename', 'plugins.pycodestyle.filename', list), + ('hang-closing', 'plugins.pycodestyle.hangClosing', bool), + ('ignore', 'plugins.pycodestyle.ignore', list), + ('max-line-length', 'plugins.pycodestyle.maxLineLength', int), + ('select', 'plugins.pycodestyle.select', list), + ('aggressive', 'plugins.pycodestyle.aggressive', int), +] + + +class PyCodeStyleConfig(ConfigSource): + + def user_config(self): + config = self.read_config_from_files(USER_CONFIGS) + return self.parse_config(config, CONFIG_KEY, OPTIONS) + + def project_config(self, document_path): + files = find_parents(self.root_path, document_path, PROJECT_CONFIGS) + config = self.read_config_from_files(files) + return self.parse_config(config, CONFIG_KEY, OPTIONS) diff --git a/external-deps/python-language-server/pyls/config/source.py b/external-deps/python-language-server/pyls/config/source.py new file mode 100644 index 00000000000..c3442e01044 --- /dev/null +++ b/external-deps/python-language-server/pyls/config/source.py @@ -0,0 +1,86 @@ +# Copyright 2017 Palantir Technologies, Inc. +import configparser +import logging +import os +import sys + +log = logging.getLogger(__name__) + + +class ConfigSource(object): + """Base class for implementing a config source.""" + + def __init__(self, root_path): + self.root_path = root_path + self.is_windows = sys.platform == 'win32' + self.xdg_home = os.environ.get( + 'XDG_CONFIG_HOME', os.path.expanduser('~/.config') + ) + + def user_config(self): + """Return user-level (i.e. home directory) configuration.""" + raise NotImplementedError() + + def project_config(self, document_path): + """Return project-level (i.e. workspace directory) configuration.""" + raise NotImplementedError() + + @staticmethod + def read_config_from_files(files): + config = configparser.RawConfigParser() + for filename in files: + if os.path.exists(filename) and not os.path.isdir(filename): + config.read(filename) + + return config + + @staticmethod + def parse_config(config, key, options): + """Parse the config with the given options.""" + conf = {} + for source, destination, opt_type in options: + opt_value = _get_opt(config, key, source, opt_type) + if opt_value is not None: + _set_opt(conf, destination, opt_value) + return conf + + +def _get_opt(config, key, option, opt_type): + """Get an option from a configparser with the given type.""" + for opt_key in [option, option.replace('-', '_')]: + if not config.has_option(key, opt_key): + continue + + if opt_type == bool: + return config.getboolean(key, opt_key) + + if opt_type == int: + return config.getint(key, opt_key) + + if opt_type == str: + return config.get(key, opt_key) + + if opt_type == list: + return _parse_list_opt(config.get(key, opt_key)) + + raise ValueError("Unknown option type: %s" % opt_type) + + +def _parse_list_opt(string): + return [s.strip() for s in string.split(",") if s.strip()] + + +def _set_opt(config_dict, path, value): + """Set the value in the dictionary at the given path if the value is not None.""" + if value is None: + return + + if '.' not in path: + config_dict[path] = value + return + + key, rest = path.split(".", 1) + if key not in config_dict: + config_dict[key] = {} + + _set_opt(config_dict[key], rest, value) diff --git a/external-deps/python-language-server/pyls/hookspecs.py b/external-deps/python-language-server/pyls/hookspecs.py new file mode 100644 index 00000000000..21f2006e79b --- /dev/null +++ b/external-deps/python-language-server/pyls/hookspecs.py @@ -0,0 +1,122 @@ +# Copyright 2017 Palantir Technologies, Inc. +# pylint: disable=redefined-builtin, unused-argument +from pyls import hookspec + + +@hookspec +def pyls_code_actions(config, workspace, document, range, context): + pass + + +@hookspec +def pyls_code_lens(config, workspace, document): + pass + + +@hookspec +def pyls_commands(config, workspace): + """The list of command strings supported by the server. + + Returns: + List[str]: The supported commands. + """ + + +@hookspec +def pyls_completions(config, workspace, document, position): + pass + + +@hookspec +def pyls_definitions(config, workspace, document, position): + pass + + +@hookspec +def pyls_dispatchers(config, workspace): + pass + + +@hookspec +def pyls_document_did_open(config, workspace, document): + pass + + +@hookspec +def pyls_document_did_save(config, workspace, document): + pass + + +@hookspec +def pyls_document_highlight(config, workspace, document, position): + pass + + +@hookspec +def pyls_document_symbols(config, workspace, document): + pass + + +@hookspec(firstresult=True) +def pyls_execute_command(config, workspace, command, arguments): + pass + + +@hookspec +def pyls_experimental_capabilities(config, workspace): + pass + + +@hookspec(firstresult=True) +def pyls_folding_range(config, workspace, document): + pass + + +@hookspec(firstresult=True) +def pyls_format_document(config, workspace, document): + pass + + +@hookspec(firstresult=True) +def pyls_format_range(config, workspace, document, range): + pass + + +@hookspec(firstresult=True) +def pyls_hover(config, workspace, document, position): + pass + + +@hookspec +def pyls_initialize(config, workspace): + pass + + +@hookspec +def pyls_initialized(): + pass + + +@hookspec +def pyls_lint(config, workspace, document, is_saved): + pass + + +@hookspec +def pyls_references(config, workspace, document, position, exclude_declaration): + pass + + +@hookspec(firstresult=True) +def pyls_rename(config, workspace, document, position, new_name): + pass + + +@hookspec +def pyls_settings(config): + pass + + +@hookspec(firstresult=True) +def pyls_signature_help(config, workspace, document, position): + pass diff --git a/external-deps/python-language-server/pyls/lsp.py b/external-deps/python-language-server/pyls/lsp.py new file mode 100644 index 00000000000..a3f88d38ca4 --- /dev/null +++ b/external-deps/python-language-server/pyls/lsp.py @@ -0,0 +1,85 @@ +# Copyright 2017 Palantir Technologies, Inc. +"""Some Language Server Protocol constants + +https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md +""" + + +class CompletionItemKind(object): + Text = 1 + Method = 2 + Function = 3 + Constructor = 4 + Field = 5 + Variable = 6 + Class = 7 + Interface = 8 + Module = 9 + Property = 10 + Unit = 11 + Value = 12 + Enum = 13 + Keyword = 14 + Snippet = 15 + Color = 16 + File = 17 + Reference = 18 + Folder = 19 + EnumMember = 20 + Constant = 21 + Struct = 22 + Event = 23 + Operator = 24 + TypeParameter = 25 + + +class DocumentHighlightKind(object): + Text = 1 + Read = 2 + Write = 3 + + +class DiagnosticSeverity(object): + Error = 1 + Warning = 2 + Information = 3 + Hint = 4 + + +class InsertTextFormat(object): + PlainText = 1 + Snippet = 2 + + +class MessageType(object): + Error = 1 + Warning = 2 + Info = 3 + Log = 4 + + +class SymbolKind(object): + File = 1 + Module = 2 + Namespace = 3 + Package = 4 + Class = 5 + Method = 6 + Property = 7 + Field = 8 + Constructor = 9 + Enum = 10 + Interface = 11 + Function = 12 + Variable = 13 + Constant = 14 + String = 15 + Number = 16 + Boolean = 17 + Array = 18 + + +class TextDocumentSyncKind(object): + NONE = 0 + FULL = 1 + INCREMENTAL = 2 diff --git a/external-deps/python-language-server/pyls/plugins/__init__.py b/external-deps/python-language-server/pyls/plugins/__init__.py new file mode 100644 index 00000000000..9c6eb52c2ac --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/__init__.py @@ -0,0 +1 @@ +# Copyright 2017 Palantir Technologies, Inc. diff --git a/external-deps/python-language-server/pyls/plugins/autopep8_format.py b/external-deps/python-language-server/pyls/plugins/autopep8_format.py new file mode 100644 index 00000000000..1e4e4e1a44c --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/autopep8_format.py @@ -0,0 +1,64 @@ +# Copyright 2018 Palantir Technologies, Inc. +import logging +from autopep8 import fix_code +from pyls import hookimpl + +log = logging.getLogger(__name__) + + +@hookimpl(tryfirst=True) # Prefer autopep8 over YAPF +def pyls_format_document(config, document): + log.info("Formatting document %s with autopep8", document) + return _format(config, document) + + +@hookimpl(tryfirst=True) # Prefer autopep8 over YAPF +def pyls_format_range(config, document, range): # pylint: disable=redefined-builtin + log.info("Formatting document %s in range %s with autopep8", document, range) + + # First we 'round' the range up/down to full lines only + range['start']['character'] = 0 + range['end']['line'] += 1 + range['end']['character'] = 0 + + # Add 1 for 1-indexing vs LSP's 0-indexing + line_range = (range['start']['line'] + 1, range['end']['line'] + 1) + return _format(config, document, line_range=line_range) + + +def _format(config, document, line_range=None): + options = _autopep8_config(config) + if line_range: + options['line_range'] = list(line_range) + + new_source = fix_code(document.source, options=options) + + if new_source == document.source: + return [] + + # I'm too lazy at the moment to parse diffs into TextEdit items + # So let's just return the entire file... + return [{ + 'range': { + 'start': {'line': 0, 'character': 0}, + # End char 0 of the line after our document + 'end': {'line': len(document.lines), 'character': 0} + }, + 'newText': new_source + }] + + +def _autopep8_config(config): + # We user pycodestyle settings to avoid redefining things + settings = config.plugin_settings('pycodestyle') + options = { + 'exclude': settings.get('exclude'), + 'hang_closing': settings.get('hangClosing'), + 'ignore': settings.get('ignore'), + 'max_line_length': settings.get('maxLineLength'), + 'select': settings.get('select'), + 'aggressive': settings.get('aggressive'), + } + + # Filter out null options + return {k: v for k, v in options.items() if v} diff --git a/external-deps/python-language-server/pyls/plugins/definition.py b/external-deps/python-language-server/pyls/plugins/definition.py new file mode 100644 index 00000000000..d4c131798e0 --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/definition.py @@ -0,0 +1,35 @@ +# Copyright 2017 Palantir Technologies, Inc. +import logging +from pyls import hookimpl, uris, _utils + +log = logging.getLogger(__name__) + + +@hookimpl +def pyls_definitions(config, document, position): + settings = config.plugin_settings('jedi_definition') + 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), + **code_position) + + return [ + { + 'uri': uris.uri_with(document.uri, path=d.module_path), + 'range': { + 'start': {'line': d.line - 1, 'character': d.column}, + 'end': {'line': d.line - 1, 'character': d.column + len(d.name)}, + } + } + for d in definitions if d.is_definition() and _not_internal_definition(d) + ] + + +def _not_internal_definition(definition): + return ( + definition.line is not None and + definition.column is not None and + definition.module_path is not None and + not definition.in_builtin_module() + ) diff --git a/external-deps/python-language-server/pyls/plugins/flake8_lint.py b/external-deps/python-language-server/pyls/plugins/flake8_lint.py new file mode 100644 index 00000000000..9bd8ae26fef --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/flake8_lint.py @@ -0,0 +1,154 @@ +# Copyright 2019 Palantir Technologies, Inc. +"""Linter pluging for flake8""" +import logging +from os import path +import re +from subprocess import Popen, PIPE +from pyls import hookimpl, lsp + +log = logging.getLogger(__name__) + + +@hookimpl +def pyls_settings(): + # Default flake8 to disabled + return {'plugins': {'flake8': {'enabled': False}}} + + +@hookimpl +def pyls_lint(config, document): + settings = config.plugin_settings('flake8') + log.debug("Got flake8 settings: %s", settings) + + opts = { + 'config': settings.get('config'), + 'exclude': settings.get('exclude'), + 'filename': settings.get('filename'), + 'hang-closing': settings.get('hangClosing'), + 'ignore': settings.get('ignore'), + 'max-line-length': settings.get('maxLineLength'), + 'select': settings.get('select'), + } + + # flake takes only absolute path to the config. So we should check and + # convert if necessary + if opts.get('config') and not path.isabs(opts.get('config')): + opts['config'] = path.abspath(path.expanduser(path.expandvars( + opts.get('config') + ))) + log.debug("using flake8 with config: %s", opts['config']) + + # Call the flake8 utility then parse diagnostics from stdout + args = build_args(opts, document.path) + output = run_flake8(args) + return parse_stdout(document, output) + + +def run_flake8(args): + """Run flake8 with the provided arguments, logs errors + from stderr if any. + """ + log.debug("Calling flake8 with args: '%s'", args) + try: + cmd = ['flake8'] + cmd.extend(args) + p = Popen(cmd, stdout=PIPE, stderr=PIPE) + except IOError: + log.debug("Can't execute flake8. Trying with 'python -m flake8'") + cmd = ['python', '-m', 'flake8'] + cmd.extend(args) + p = Popen(cmd, stdout=PIPE, stderr=PIPE) + (stdout, stderr) = p.communicate() + if stderr: + log.error("Error while running flake8 '%s'", stderr.decode()) + return stdout.decode() + + +def build_args(options, doc_path): + """Build arguments for calling flake8. + + Args: + options: dictionary of argument names and their values. + doc_path: path of the document to lint. + """ + args = [doc_path] + for arg_name, arg_val in options.items(): + if arg_val is None: + continue + arg = None + if isinstance(arg_val, list): + arg = '--{}={}'.format(arg_name, ','.join(arg_val)) + elif isinstance(arg_val, bool): + if arg_val: + arg = '--{}'.format(arg_name) + else: + arg = '--{}={}'.format(arg_name, arg_val) + args.append(arg) + return args + + +def parse_stdout(document, stdout): + """ + Build a diagnostics from flake8's output, it should extract every result and format + it into a dict that looks like this: + { + 'source': 'flake8', + 'code': code, # 'E501' + 'range': { + 'start': { + 'line': start_line, + 'character': start_column, + }, + 'end': { + 'line': end_line, + 'character': end_column, + }, + }, + 'message': msg, + 'severity': lsp.DiagnosticSeverity.*, + } + + Args: + document: The document to be linted. + stdout: output from flake8 + Returns: + A list of dictionaries. + """ + + diagnostics = [] + lines = stdout.splitlines() + for raw_line in lines: + parsed_line = re.match(r'(.*):(\d*):(\d*): (\w*) (.*)', raw_line) + if not parsed_line: + log.debug("Flake8 output parser can't parse line '%s'", raw_line) + continue + + parsed_line = parsed_line.groups() + if len(parsed_line) != 5: + log.debug("Flake8 output parser can't parse line '%s'", raw_line) + continue + + _, line, character, code, msg = parsed_line + line = int(line) - 1 + character = int(character) - 1 + diagnostics.append( + { + 'source': 'flake8', + 'code': code, + 'range': { + 'start': { + 'line': line, + 'character': character + }, + 'end': { + 'line': line, + # no way to determine the column + 'character': len(document.lines[line]) + } + }, + 'message': msg, + 'severity': lsp.DiagnosticSeverity.Warning, + } + ) + + return diagnostics diff --git a/external-deps/python-language-server/pyls/plugins/folding.py b/external-deps/python-language-server/pyls/plugins/folding.py new file mode 100644 index 00000000000..dd476dcb98d --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/folding.py @@ -0,0 +1,203 @@ +# pylint: disable=len-as-condition +# Copyright 2019 Palantir Technologies, Inc. + +import re + +import parso +import parso.python.tree as tree_nodes + +from pyls import hookimpl + +SKIP_NODES = (tree_nodes.Module, tree_nodes.IfStmt, tree_nodes.TryStmt) +IDENTATION_REGEX = re.compile(r'(\s+).+') + + +@hookimpl +def pyls_folding_range(document): + program = document.source + '\n' + lines = program.splitlines() + tree = parso.parse(program) + ranges = __compute_folding_ranges(tree, lines) + + results = [] + for (start_line, end_line) in ranges: + start_line -= 1 + end_line -= 1 + # If start/end character is not defined, then it defaults to the + # corresponding line last character + results.append({ + 'startLine': start_line, + 'endLine': end_line, + }) + return results + + +def __merge_folding_ranges(left, right): + for start in list(left.keys()): + right_start = right.pop(start, None) + if right_start is not None: + left[start] = max(right_start, start) + left.update(right) + return left + + +def __empty_identation_stack(identation_stack, level_limits, + current_line, folding_ranges): + while identation_stack != []: + upper_level = identation_stack.pop(0) + level_start = level_limits.pop(upper_level) + folding_ranges.append((level_start, current_line)) + return folding_ranges + + +def __match_identation_stack(identation_stack, level, level_limits, + folding_ranges, current_line): + upper_level = identation_stack.pop(0) + while upper_level >= level: + level_start = level_limits.pop(upper_level) + folding_ranges.append((level_start, current_line)) + upper_level = identation_stack.pop(0) + identation_stack.insert(0, upper_level) + return identation_stack, folding_ranges + + +def __compute_folding_ranges_identation(text): + lines = text.splitlines() + folding_ranges = [] + identation_stack = [] + level_limits = {} + current_level = 0 + current_line = 0 + while lines[current_line] == '': + current_line += 1 + for i, line in enumerate(lines): + if i < current_line: + continue + i += 1 + identation_match = IDENTATION_REGEX.match(line) + if identation_match is not None: + whitespace = identation_match.group(1) + level = len(whitespace) + if level > current_level: + level_limits[current_level] = current_line + identation_stack.insert(0, current_level) + current_level = level + elif level < current_level: + identation_stack, folding_ranges = __match_identation_stack( + identation_stack, level, level_limits, folding_ranges, + current_line) + current_level = level + else: + folding_ranges = __empty_identation_stack( + identation_stack, level_limits, current_line, folding_ranges) + current_level = 0 + if line.strip() != '': + current_line = i + folding_ranges = __empty_identation_stack( + identation_stack, level_limits, current_line, folding_ranges) + return dict(folding_ranges) + + +def __check_if_node_is_valid(node): + valid = True + if isinstance(node, tree_nodes.PythonNode): + kind = node.type + valid = kind not in {'decorated', 'parameters', 'dictorsetmaker', + 'testlist_comp'} + if kind == 'suite': + if isinstance(node.parent, tree_nodes.Function): + valid = False + return valid + + +def __handle_skip(stack, skip): + body = stack[skip] + children = [body] + if hasattr(body, 'children'): + children = body.children + stack = stack[:skip] + children + stack[skip + 1:] + node = body + end_line, _ = body.end_pos + return node, end_line + + +def __handle_flow_nodes(node, end_line, stack): + from_keyword = False + if isinstance(node, tree_nodes.Keyword): + from_keyword = True + if node.value in {'if', 'elif', 'with', 'while'}: + node, end_line = __handle_skip(stack, 2) + elif node.value in {'except'}: + first_node = stack[0] + if isinstance(first_node, tree_nodes.Operator): + node, end_line = __handle_skip(stack, 1) + else: + node, end_line = __handle_skip(stack, 2) + elif node.value in {'for'}: + node, end_line = __handle_skip(stack, 4) + elif node.value in {'else'}: + node, end_line = __handle_skip(stack, 1) + return end_line, from_keyword, node, stack + + +def __compute_start_end_lines(node, stack): + start_line, _ = node.start_pos + end_line, _ = node.end_pos + modified = False + end_line, from_keyword, node, stack = __handle_flow_nodes( + node, end_line, stack) + + last_leaf = node.get_last_leaf() + last_newline = isinstance(last_leaf, tree_nodes.Newline) + last_operator = isinstance(last_leaf, tree_nodes.Operator) + node_is_operator = isinstance(node, tree_nodes.Operator) + last_operator = last_operator or not node_is_operator + + end_line -= 1 + + if isinstance(node.parent, tree_nodes.PythonNode) and not from_keyword: + kind = node.type + if kind in {'suite', 'atom', 'atom_expr', 'arglist'}: + if len(stack) > 0: + next_node = stack[0] + next_line, _ = next_node.start_pos + if next_line > end_line: + end_line += 1 + modified = True + if not last_newline and not modified and not last_operator: + end_line += 1 + return start_line, end_line, stack + + +def __compute_folding_ranges(tree, lines): + folding_ranges = {} + stack = [tree] + + while len(stack) > 0: + node = stack.pop(0) + if isinstance(node, tree_nodes.Newline): + # Skip newline nodes + continue + elif isinstance(node, tree_nodes.PythonErrorNode): + # Fallback to identation-based (best-effort) folding + start_line, _ = node.start_pos + start_line -= 1 + padding = [''] * start_line + text = '\n'.join(padding + lines[start_line:]) + '\n' + identation_ranges = __compute_folding_ranges_identation(text) + folding_ranges = __merge_folding_ranges( + folding_ranges, identation_ranges) + break + elif not isinstance(node, SKIP_NODES): + valid = __check_if_node_is_valid(node) + if valid: + start_line, end_line, stack = __compute_start_end_lines( + node, stack) + if end_line > start_line: + current_end = folding_ranges.get(start_line, -1) + folding_ranges[start_line] = max(current_end, end_line) + if hasattr(node, 'children'): + stack = node.children + stack + + folding_ranges = sorted(folding_ranges.items()) + return folding_ranges diff --git a/external-deps/python-language-server/pyls/plugins/highlight.py b/external-deps/python-language-server/pyls/plugins/highlight.py new file mode 100644 index 00000000000..4c4c195c16b --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/highlight.py @@ -0,0 +1,25 @@ +# Copyright 2017 Palantir Technologies, Inc. +import logging +from pyls import hookimpl, lsp, _utils + +log = logging.getLogger(__name__) + + +@hookimpl +def pyls_document_highlight(document, position): + 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 + + def local_to_document(definition): + return not definition.module_path or definition.module_path == document.path + + return [{ + 'range': { + 'start': {'line': d.line - 1, 'character': d.column}, + 'end': {'line': d.line - 1, 'character': d.column + len(d.name)} + }, + 'kind': lsp.DocumentHighlightKind.Write if d.is_definition() else lsp.DocumentHighlightKind.Read + } for d in usages if is_valid(d) and local_to_document(d)] diff --git a/external-deps/python-language-server/pyls/plugins/hover.py b/external-deps/python-language-server/pyls/plugins/hover.py new file mode 100644 index 00000000000..9332a52dcf9 --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/hover.py @@ -0,0 +1,48 @@ +# Copyright 2017 Palantir Technologies, Inc. + +import logging + +from pyls import hookimpl, _utils + +log = logging.getLogger(__name__) + + +@hookimpl +def pyls_hover(document, position): + code_position = _utils.position_to_jedi_linecolumn(document, position) + definitions = document.jedi_script().infer(**code_position) + word = document.word_at_position(position) + + # 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/external-deps/python-language-server/pyls/plugins/jedi_completion.py b/external-deps/python-language-server/pyls/plugins/jedi_completion.py new file mode 100644 index 00000000000..921df628d8b --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/jedi_completion.py @@ -0,0 +1,204 @@ +# Copyright 2017 Palantir Technologies, Inc. +import logging +import os.path as osp + +import parso + +from pyls import _utils, hookimpl, lsp + +log = logging.getLogger(__name__) + +# Map to the VSCode type +_TYPE_MAP = { + 'none': lsp.CompletionItemKind.Value, + 'type': lsp.CompletionItemKind.Class, + 'tuple': lsp.CompletionItemKind.Class, + 'dict': lsp.CompletionItemKind.Class, + 'dictionary': lsp.CompletionItemKind.Class, + 'function': lsp.CompletionItemKind.Function, + 'lambda': lsp.CompletionItemKind.Function, + 'generator': lsp.CompletionItemKind.Function, + 'class': lsp.CompletionItemKind.Class, + 'instance': lsp.CompletionItemKind.Reference, + 'method': lsp.CompletionItemKind.Method, + 'builtin': lsp.CompletionItemKind.Class, + 'builtinfunction': lsp.CompletionItemKind.Function, + 'module': lsp.CompletionItemKind.Module, + 'file': lsp.CompletionItemKind.File, + 'path': lsp.CompletionItemKind.Text, + 'xrange': lsp.CompletionItemKind.Class, + 'slice': lsp.CompletionItemKind.Class, + 'traceback': lsp.CompletionItemKind.Class, + 'frame': lsp.CompletionItemKind.Class, + 'buffer': lsp.CompletionItemKind.Class, + 'dictproxy': lsp.CompletionItemKind.Class, + 'funcdef': lsp.CompletionItemKind.Function, + 'property': lsp.CompletionItemKind.Property, + 'import': lsp.CompletionItemKind.Module, + 'keyword': lsp.CompletionItemKind.Keyword, + 'constant': lsp.CompletionItemKind.Variable, + 'variable': lsp.CompletionItemKind.Variable, + 'value': lsp.CompletionItemKind.Value, + 'param': lsp.CompletionItemKind.Variable, + 'statement': lsp.CompletionItemKind.Keyword, +} + +# Types of parso nodes for which snippet is not included in the completion +_IMPORTS = ('import_name', 'import_from') + +# Types of parso node for errors +_ERRORS = ('error_node', ) + + +@hookimpl +def pyls_completions(config, document, position): + """Get formatted completions for current code position""" + settings = config.plugin_settings('jedi_completion', document_path=document.path) + code_position = _utils.position_to_jedi_linecolumn(document, position) + + code_position["fuzzy"] = settings.get("fuzzy", False) + completions = document.jedi_script().complete(**code_position) + + if not completions: + return None + + completion_capabilities = config.capabilities.get('textDocument', {}).get('completion', {}) + snippet_support = completion_capabilities.get('completionItem', {}).get('snippetSupport') + + should_include_params = settings.get('include_params') + should_include_class_objects = settings.get('include_class_objects', True) + + 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) + + ready_completions = [ + _format_completion(c, include_params) + for c in completions + ] + + if include_class_objects: + for c in completions: + if c.type == 'class': + completion_dict = _format_completion(c, False) + completion_dict['kind'] = lsp.CompletionItemKind.TypeParameter + completion_dict['label'] += ' object' + ready_completions.append(completion_dict) + + return ready_completions or None + + +def is_exception_class(name): + """ + Determine if a class name is an instance of an Exception. + + This returns `False` if the name given corresponds with a instance of + the 'Exception' class, `True` otherwise + """ + try: + return name in [cls.__name__ for cls in Exception.__subclasses__()] + except AttributeError: + # Needed in case a class don't uses new-style + # class definition in Python 2 + return False + + +def use_snippets(document, position): + """ + Determine if it's necessary to return snippets in code completions. + + This returns `False` if a completion is being requested on an import + statement, `True` otherwise. + """ + line = position['line'] + lines = document.source.split('\n', line) + act_lines = [lines[line][:position['character']]] + line -= 1 + last_character = '' + while line > -1: + act_line = lines[line] + if (act_line.rstrip().endswith('\\') or + act_line.rstrip().endswith('(') or + act_line.rstrip().endswith(',')): + act_lines.insert(0, act_line) + line -= 1 + if act_line.rstrip().endswith('('): + # Needs to be added to the end of the code before parsing + # to make it valid, otherwise the node type could end + # being an 'error_node' for multi-line imports that use '(' + last_character = ')' + else: + break + if '(' in act_lines[-1].strip(): + last_character = ')' + code = '\n'.join(act_lines).split(';')[-1].strip() + last_character + tokens = parso.parse(code) + expr_type = tokens.children[0].type + return (expr_type not in _IMPORTS and + not (expr_type in _ERRORS and 'import' in code)) + + +def _format_completion(d, include_params=True): + completion = { + 'label': _label(d), + 'kind': _TYPE_MAP.get(d.type), + 'detail': _detail(d), + 'documentation': _utils.format_docstring(d.docstring()), + 'sortText': _sort_text(d), + 'insertText': d.name + } + + if d.type == 'path': + path = osp.normpath(d.name) + path = path.replace('\\', '\\\\') + path = path.replace('/', '\\/') + completion['insertText'] = path + + 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 {'/', '*'}] + + if len(positional_args) > 1: + # For completions with params, we can generate a snippet instead + completion['insertTextFormat'] = lsp.InsertTextFormat.Snippet + snippet = d.name + '(' + for i, param in enumerate(positional_args): + snippet += '${%s:%s}' % (i + 1, param.name) + if i < len(positional_args) - 1: + snippet += ', ' + snippet += ')$0' + completion['insertText'] = snippet + elif len(positional_args) == 1: + completion['insertTextFormat'] = lsp.InsertTextFormat.Snippet + completion['insertText'] = d.name + '($0)' + else: + completion['insertText'] = d.name + '()' + + return completion + + +def _label(definition): + 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 + + +def _detail(definition): + try: + return definition.parent().full_name or '' + except AttributeError: + return definition.full_name or '' + + +def _sort_text(definition): + """ Ensure builtins appear at the bottom. + Description is of format : . + """ + + # If its 'hidden', put it next last + prefix = 'z{}' if definition.name.startswith('_') else 'a{}' + return prefix.format(definition.name) diff --git a/external-deps/python-language-server/pyls/plugins/jedi_rename.py b/external-deps/python-language-server/pyls/plugins/jedi_rename.py new file mode 100644 index 00000000000..2e633d71a29 --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/jedi_rename.py @@ -0,0 +1,48 @@ +# Copyright 2020 Palantir Technologies, Inc. +import logging + +from pyls import hookimpl, uris, _utils + +log = logging.getLogger(__name__) + + +@hookimpl +def pyls_rename(config, workspace, document, position, new_name): # pylint: disable=unused-argument + log.debug('Executing rename of %s to %s', document.word_at_position(position), new_name) + kwargs = _utils.position_to_jedi_linecolumn(document, position) + kwargs['new_name'] = new_name + try: + refactoring = document.jedi_script().rename(**kwargs) + except NotImplementedError: + raise Exception('No support for renaming in Python 2/3.5 with Jedi. ' + 'Consider using the rope_rename plugin instead') + log.debug('Finished rename: %s', refactoring.get_diff()) + + return { + 'documentChanges': [ + { + 'textDocument': { + 'uri': uris.uri_with(document.uri, path=file_path), + 'version': workspace.get_document(document.uri).version, + }, + 'edits': [ + { + 'range': { + 'start': {'line': 0, 'character': 0}, + 'end': { + 'line': _num_lines(changed_file.get_new_code()), + 'character': 0, + }, + }, + 'newText': changed_file.get_new_code(), + } + ], + } + for file_path, changed_file in refactoring.get_changed_files().items() + ], + } + + +def _num_lines(file_contents): + 'Count the number of lines in the given string.' + return len(file_contents.splitlines()) diff --git a/external-deps/python-language-server/pyls/plugins/mccabe_lint.py b/external-deps/python-language-server/pyls/plugins/mccabe_lint.py new file mode 100644 index 00000000000..31fb39a9819 --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/mccabe_lint.py @@ -0,0 +1,40 @@ +# Copyright 2017 Palantir Technologies, Inc. +import ast +import logging +import mccabe +from pyls import hookimpl, lsp + +log = logging.getLogger(__name__) + +THRESHOLD = 'threshold' +DEFAULT_THRESHOLD = 15 + + +@hookimpl +def pyls_lint(config, document): + threshold = config.plugin_settings('mccabe').get(THRESHOLD, DEFAULT_THRESHOLD) + log.debug("Running mccabe lint with threshold: %s", threshold) + + try: + tree = compile(document.source, document.path, "exec", ast.PyCF_ONLY_AST) + except SyntaxError: + # We'll let the other linters point this one out + return None + + visitor = mccabe.PathGraphingAstVisitor() + visitor.preorder(tree, visitor) + + diags = [] + for graph in visitor.graphs.values(): + if graph.complexity() >= threshold: + diags.append({ + 'source': 'mccabe', + 'range': { + 'start': {'line': graph.lineno - 1, 'character': graph.column}, + 'end': {'line': graph.lineno - 1, 'character': len(document.lines[graph.lineno])}, + }, + 'message': 'Cyclomatic complexity too high: %s (threshold %s)' % (graph.complexity(), threshold), + 'severity': lsp.DiagnosticSeverity.Warning + }) + + return diags diff --git a/external-deps/python-language-server/pyls/plugins/preload_imports.py b/external-deps/python-language-server/pyls/plugins/preload_imports.py new file mode 100644 index 00000000000..b00552cff1a --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/preload_imports.py @@ -0,0 +1,34 @@ +# Copyright 2017 Palantir Technologies, Inc. +import logging +from pyls import hookimpl + +log = logging.getLogger(__name__) + +MODULES = [ + "OpenGL", "PIL", + "array", "audioop", "binascii", "cPickle", "cStringIO", "cmath", "collections", + "datetime", "errno", "exceptions", "gc", "imageop", "imp", "itertools", + "marshal", "math", "matplotlib", "mmap", "mpmath", "msvcrt", "networkx", "nose", "nt", + "numpy", "operator", "os", "os.path", "pandas", "parser", "rgbimg", "scipy", "signal", + "skimage", "sklearn", "statsmodels", "strop", "sympy", "sys", "thread", "time", + "wx", "xxsubtype", "zipimport", "zlib" +] + + +@hookimpl +def pyls_settings(): + # Setup default modules to preload, and rope extension modules + return { + 'plugins': {'preload': {'modules': MODULES}}, + 'rope': {'extensionModules': MODULES} + } + + +@hookimpl +def pyls_initialize(config): + for mod_name in config.plugin_settings('preload').get('modules', []): + try: + __import__(mod_name) + log.debug("Preloaded module %s", mod_name) + except ImportError: + pass diff --git a/external-deps/python-language-server/pyls/plugins/pycodestyle_lint.py b/external-deps/python-language-server/pyls/plugins/pycodestyle_lint.py new file mode 100644 index 00000000000..490b65d31ee --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/pycodestyle_lint.py @@ -0,0 +1,81 @@ +# Copyright 2017 Palantir Technologies, Inc. +import logging +import pycodestyle +from pyls import hookimpl, lsp + +try: + from autopep8 import continued_indentation as autopep8_c_i +except ImportError: + pass +else: + # Check if autopep8's continued_indentation implementation + # is overriding pycodestyle's and if so, re-register + # the check using pycodestyle's implementation as expected + if autopep8_c_i in pycodestyle._checks['logical_line']: + del pycodestyle._checks['logical_line'][autopep8_c_i] + pycodestyle.register_check(pycodestyle.continued_indentation) + +log = logging.getLogger(__name__) + + +@hookimpl +def pyls_lint(config, document): + settings = config.plugin_settings('pycodestyle') + log.debug("Got pycodestyle settings: %s", settings) + + opts = { + 'exclude': settings.get('exclude'), + 'filename': settings.get('filename'), + 'hang_closing': settings.get('hangClosing'), + 'ignore': settings.get('ignore'), + 'max_line_length': settings.get('maxLineLength'), + 'select': settings.get('select'), + } + kwargs = {k: v for k, v in opts.items() if v} + styleguide = pycodestyle.StyleGuide(kwargs) + + c = pycodestyle.Checker( + filename=document.uri, lines=document.lines, options=styleguide.options, + report=PyCodeStyleDiagnosticReport(styleguide.options) + ) + c.check_all() + diagnostics = c.report.diagnostics + + return diagnostics + + +class PyCodeStyleDiagnosticReport(pycodestyle.BaseReport): + + def __init__(self, options): + self.diagnostics = [] + super(PyCodeStyleDiagnosticReport, self).__init__(options=options) + + def error(self, line_number, offset, text, check): + code = text[:4] + if self._ignore_code(code): + return + + # Don't care about expected errors or warnings + if code in self.expected: + return + + # PyCodeStyle will sometimes give you an error the line after the end of the file + # e.g. no newline at end of file + # In that case, the end offset should just be some number ~100 + # (because why not? There's nothing to underline anyways) + err_range = { + 'start': {'line': line_number - 1, 'character': offset}, + 'end': { + # FIXME: It's a little naiive to mark until the end of the line, can we not easily do better? + 'line': line_number - 1, + 'character': 100 if line_number > len(self.lines) else len(self.lines[line_number - 1]) + }, + } + self.diagnostics.append({ + 'source': 'pycodestyle', + 'range': err_range, + 'message': text, + 'code': code, + # Are style errors really ever errors? + 'severity': lsp.DiagnosticSeverity.Warning + }) diff --git a/external-deps/python-language-server/pyls/plugins/pydocstyle_lint.py b/external-deps/python-language-server/pyls/plugins/pydocstyle_lint.py new file mode 100644 index 00000000000..d00bda95489 --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/pydocstyle_lint.py @@ -0,0 +1,119 @@ +# Copyright 2017 Palantir Technologies, Inc. +import contextlib +import logging +import os +import re +import sys + +import pydocstyle +from pyls import hookimpl, lsp + +log = logging.getLogger(__name__) + +# PyDocstyle is a little verbose in debug message +pydocstyle_logger = logging.getLogger(pydocstyle.utils.__name__) +pydocstyle_logger.setLevel(logging.INFO) + +DEFAULT_MATCH_RE = pydocstyle.config.ConfigurationParser.DEFAULT_MATCH_RE +DEFAULT_MATCH_DIR_RE = pydocstyle.config.ConfigurationParser.DEFAULT_MATCH_DIR_RE + + +@hookimpl +def pyls_settings(): + # Default pydocstyle to disabled + return {'plugins': {'pydocstyle': {'enabled': False}}} + + +@hookimpl +def pyls_lint(config, document): + settings = config.plugin_settings('pydocstyle') + log.debug("Got pydocstyle settings: %s", settings) + + # Explicitly passing a path to pydocstyle means it doesn't respect the --match flag, so do it ourselves + filename_match_re = re.compile(settings.get('match', DEFAULT_MATCH_RE) + '$') + if not filename_match_re.match(os.path.basename(document.path)): + return [] + + # Likewise with --match-dir + dir_match_re = re.compile(settings.get('matchDir', DEFAULT_MATCH_DIR_RE) + '$') + if not dir_match_re.match(os.path.basename(os.path.dirname(document.path))): + return [] + + args = [document.path] + + if settings.get('convention'): + args.append('--convention=' + settings['convention']) + + if settings.get('addSelect'): + args.append('--add-select=' + ','.join(settings['addSelect'])) + if settings.get('addIgnore'): + args.append('--add-ignore=' + ','.join(settings['addIgnore'])) + + elif settings.get('select'): + args.append('--select=' + ','.join(settings['select'])) + elif settings.get('ignore'): + args.append('--ignore=' + ','.join(settings['ignore'])) + + log.info("Using pydocstyle args: %s", args) + + conf = pydocstyle.config.ConfigurationParser() + with _patch_sys_argv(args): + # TODO(gatesn): We can add more pydocstyle args here from our pyls config + conf.parse() + + # Will only yield a single filename, the document path + diags = [] + for filename, checked_codes, ignore_decorators in conf.get_files_to_check(): + errors = pydocstyle.checker.ConventionChecker().check_source( + document.source, filename, ignore_decorators=ignore_decorators + ) + + try: + for error in errors: + if error.code not in checked_codes: + continue + diags.append(_parse_diagnostic(document, error)) + except pydocstyle.parser.ParseError: + # In the case we cannot parse the Python file, just continue + pass + + log.debug("Got pydocstyle errors: %s", diags) + return diags + + +def _parse_diagnostic(document, error): + lineno = error.definition.start - 1 + line = document.lines[0] if document.lines else "" + + start_character = len(line) - len(line.lstrip()) + end_character = len(line) + + return { + 'source': 'pydocstyle', + 'code': error.code, + 'message': error.message, + 'severity': lsp.DiagnosticSeverity.Warning, + 'range': { + 'start': { + 'line': lineno, + 'character': start_character + }, + 'end': { + 'line': lineno, + 'character': end_character + } + } + } + + +@contextlib.contextmanager +def _patch_sys_argv(arguments): + old_args = sys.argv + + # Preserve argv[0] since it's the executable + sys.argv = old_args[0:1] + arguments + + try: + yield + finally: + sys.argv = old_args diff --git a/external-deps/python-language-server/pyls/plugins/pyflakes_lint.py b/external-deps/python-language-server/pyls/plugins/pyflakes_lint.py new file mode 100644 index 00000000000..c37aad89225 --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/pyflakes_lint.py @@ -0,0 +1,80 @@ +# Copyright 2017 Palantir Technologies, Inc. +from pyflakes import api as pyflakes_api, messages +from pyls import hookimpl, lsp + +# Pyflakes messages that should be reported as Errors instead of Warns +PYFLAKES_ERROR_MESSAGES = ( + messages.UndefinedName, + messages.UndefinedExport, + messages.UndefinedLocal, + messages.DuplicateArgument, + messages.FutureFeatureNotDefined, + messages.ReturnOutsideFunction, + messages.YieldOutsideFunction, + messages.ContinueOutsideLoop, + messages.BreakOutsideLoop, + messages.ContinueInFinally, + messages.TwoStarredExpressions, +) + + +@hookimpl +def pyls_lint(document): + reporter = PyflakesDiagnosticReport(document.lines) + pyflakes_api.check(document.source.encode('utf-8'), document.path, reporter=reporter) + return reporter.diagnostics + + +class PyflakesDiagnosticReport(object): + + def __init__(self, lines): + self.lines = lines + self.diagnostics = [] + + def unexpectedError(self, _filename, msg): # pragma: no cover + err_range = { + 'start': {'line': 0, 'character': 0}, + 'end': {'line': 0, 'character': 0}, + } + self.diagnostics.append({ + 'source': 'pyflakes', + 'range': err_range, + 'message': msg, + 'severity': lsp.DiagnosticSeverity.Error, + }) + + def syntaxError(self, _filename, msg, lineno, offset, text): + # We've seen that lineno and offset can sometimes be None + lineno = lineno or 1 + offset = offset or 0 + + err_range = { + 'start': {'line': lineno - 1, 'character': offset}, + 'end': {'line': lineno - 1, 'character': offset + len(text)}, + } + self.diagnostics.append({ + 'source': 'pyflakes', + 'range': err_range, + 'message': msg, + 'severity': lsp.DiagnosticSeverity.Error, + }) + + def flake(self, message): + """ Get message like :: """ + err_range = { + 'start': {'line': message.lineno - 1, 'character': message.col}, + 'end': {'line': message.lineno - 1, 'character': len(self.lines[message.lineno - 1])}, + } + + severity = lsp.DiagnosticSeverity.Warning + for message_type in PYFLAKES_ERROR_MESSAGES: + if isinstance(message, message_type): + severity = lsp.DiagnosticSeverity.Error + break + + self.diagnostics.append({ + 'source': 'pyflakes', + 'range': err_range, + 'message': message.message % message.message_args, + 'severity': severity + }) diff --git a/external-deps/python-language-server/pyls/plugins/pylint_lint.py b/external-deps/python-language-server/pyls/plugins/pylint_lint.py new file mode 100644 index 00000000000..9a412637ba2 --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/pylint_lint.py @@ -0,0 +1,165 @@ +# Copyright 2018 Google LLC. +"""Linter plugin for pylint.""" +import collections +import logging +import sys + +from pylint.epylint import py_run +from pyls import hookimpl, lsp + +try: + import ujson as json +except Exception: # pylint: disable=broad-except + import json + +log = logging.getLogger(__name__) + + +class PylintLinter(object): + last_diags = collections.defaultdict(list) + + @classmethod + def lint(cls, document, is_saved, flags=''): + """Plugin interface to pyls linter. + + Args: + document: The document to be linted. + is_saved: Whether or not the file has been saved to disk. + flags: Additional flags to pass to pylint. Not exposed to + pyls_lint, but used for testing. + + Returns: + A list of dicts with the following format: + + { + 'source': 'pylint', + 'range': { + 'start': { + 'line': start_line, + 'character': start_column, + }, + 'end': { + 'line': end_line, + 'character': end_column, + }, + } + 'message': msg, + 'severity': lsp.DiagnosticSeverity.*, + } + """ + if not is_saved: + # Pylint can only be run on files that have been saved to disk. + # Rather than return nothing, return the previous list of + # diagnostics. If we return an empty list, any diagnostics we'd + # previously shown will be cleared until the next save. Instead, + # continue showing (possibly stale) diagnostics until the next + # save. + return cls.last_diags[document.path] + + # py_run will call shlex.split on its arguments, and shlex.split does + # not handle Windows paths (it will try to perform escaping). Turn + # backslashes into forward slashes first to avoid this issue. + path = document.path + if sys.platform.startswith('win'): + path = path.replace('\\', '/') + + pylint_call = '{} -f json {}'.format(path, flags) + log.debug("Calling pylint with '%s'", pylint_call) + json_out, err = py_run(pylint_call, return_std=True) + + # Get strings + json_out = json_out.getvalue() + err = err.getvalue() + + if err != '': + log.error("Error calling pylint: '%s'", err) + + # pylint prints nothing rather than [] when there are no diagnostics. + # json.loads will not parse an empty string, so just return. + if not json_out.strip(): + cls.last_diags[document.path] = [] + return [] + + # Pylint's JSON output is a list of objects with the following format. + # + # { + # "obj": "main", + # "path": "foo.py", + # "message": "Missing function docstring", + # "message-id": "C0111", + # "symbol": "missing-docstring", + # "column": 0, + # "type": "convention", + # "line": 5, + # "module": "foo" + # } + # + # The type can be any of: + # + # * convention + # * error + # * fatal + # * refactor + # * warning + diagnostics = [] + for diag in json.loads(json_out): + # pylint lines index from 1, pyls lines index from 0 + line = diag['line'] - 1 + + err_range = { + 'start': { + 'line': line, + # Index columns start from 0 + 'character': diag['column'], + }, + 'end': { + 'line': line, + # It's possible that we're linting an empty file. Even an empty + # file might fail linting if it isn't named properly. + 'character': len(document.lines[line]) if document.lines else 0, + }, + } + + if diag['type'] == 'convention': + severity = lsp.DiagnosticSeverity.Information + elif diag['type'] == 'error': + severity = lsp.DiagnosticSeverity.Error + elif diag['type'] == 'fatal': + severity = lsp.DiagnosticSeverity.Error + elif diag['type'] == 'refactor': + severity = lsp.DiagnosticSeverity.Hint + elif diag['type'] == 'warning': + severity = lsp.DiagnosticSeverity.Warning + + diagnostics.append({ + 'source': 'pylint', + 'range': err_range, + 'message': '[{}] {}'.format(diag['symbol'], diag['message']), + 'severity': severity, + 'code': diag['message-id'] + }) + cls.last_diags[document.path] = diagnostics + return diagnostics + + +def _build_pylint_flags(settings): + """Build arguments for calling pylint.""" + pylint_args = settings.get('args') + if pylint_args is None: + return '' + return ' '.join(pylint_args) + + +@hookimpl +def pyls_settings(): + # Default pylint to disabled because it requires a config + # file to be useful. + return {'plugins': {'pylint': {'enabled': False, 'args': []}}} + + +@hookimpl +def pyls_lint(config, document, is_saved): + settings = config.plugin_settings('pylint') + log.debug("Got pylint settings: %s", settings) + flags = _build_pylint_flags(settings) + return PylintLinter.lint(document, is_saved, flags=flags) diff --git a/external-deps/python-language-server/pyls/plugins/references.py b/external-deps/python-language-server/pyls/plugins/references.py new file mode 100644 index 00000000000..4bd47c96d59 --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/references.py @@ -0,0 +1,24 @@ +# Copyright 2017 Palantir Technologies, Inc. +import logging +from pyls import hookimpl, uris, _utils + +log = logging.getLogger(__name__) + + +@hookimpl +def pyls_references(document, position, exclude_declaration=False): + 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 + usages = [d for d in usages if not d.is_definition()] + + # Filter out builtin modules + return [{ + 'uri': uris.uri_with(document.uri, path=d.module_path) if d.module_path else document.uri, + 'range': { + 'start': {'line': d.line - 1, 'character': d.column}, + 'end': {'line': d.line - 1, 'character': d.column + len(d.name)} + } + } for d in usages if not d.in_builtin_module()] diff --git a/external-deps/python-language-server/pyls/plugins/rope_completion.py b/external-deps/python-language-server/pyls/plugins/rope_completion.py new file mode 100644 index 00000000000..e556e464e8d --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/rope_completion.py @@ -0,0 +1,107 @@ +# Copyright 2017 Palantir Technologies, Inc. +import logging +from rope.contrib.codeassist import code_assist, sorted_proposals + +from pyls import hookimpl, lsp + + +log = logging.getLogger(__name__) + + +@hookimpl +def pyls_settings(): + # Default rope_completion to disabled + return {'plugins': {'rope_completion': {'enabled': False}}} + + +@hookimpl +def pyls_completions(config, workspace, document, position): + # Rope is a bit rubbish at completing module imports, so we'll return None + word = document.word_at_position({ + # The -1 should really be trying to look at the previous word, but that might be quite expensive + # So we only skip import completions when the cursor is one space after `import` + 'line': position['line'], 'character': max(position['character'] - 1, 0), + }) + if word == 'import': + return None + + offset = document.offset_at_position(position) + rope_config = config.settings(document_path=document.path).get('rope', {}) + rope_project = workspace._rope_project_builder(rope_config) + document_rope = document._rope_resource(rope_config) + + try: + definitions = code_assist(rope_project, document.source, offset, document_rope, maxfixes=3) + except Exception as e: # pylint: disable=broad-except + log.debug("Failed to run Rope code assist: %s", e) + return [] + + definitions = sorted_proposals(definitions) + new_definitions = [] + for d in definitions: + try: + doc = d.get_doc() + except AttributeError: + doc = None + new_definitions.append({ + 'label': d.name, + 'kind': _kind(d), + 'detail': '{0} {1}'.format(d.scope or "", d.name), + 'documentation': doc or "", + 'sortText': _sort_text(d) + }) + definitions = new_definitions + + return definitions or None + + +def _sort_text(definition): + """ Ensure builtins appear at the bottom. + Description is of format : . + """ + if definition.name.startswith("_"): + # It's a 'hidden' func, put it next last + return 'z' + definition.name + elif definition.scope == 'builtin': + return 'y' + definition.name + + # Else put it at the front + return 'a' + definition.name + + +def _kind(d): + """ Return the VSCode type """ + MAP = { + 'none': lsp.CompletionItemKind.Value, + 'type': lsp.CompletionItemKind.Class, + 'tuple': lsp.CompletionItemKind.Class, + 'dict': lsp.CompletionItemKind.Class, + 'dictionary': lsp.CompletionItemKind.Class, + 'function': lsp.CompletionItemKind.Function, + 'lambda': lsp.CompletionItemKind.Function, + 'generator': lsp.CompletionItemKind.Function, + 'class': lsp.CompletionItemKind.Class, + 'instance': lsp.CompletionItemKind.Reference, + 'method': lsp.CompletionItemKind.Method, + 'builtin': lsp.CompletionItemKind.Class, + 'builtinfunction': lsp.CompletionItemKind.Function, + 'module': lsp.CompletionItemKind.Module, + 'file': lsp.CompletionItemKind.File, + 'xrange': lsp.CompletionItemKind.Class, + 'slice': lsp.CompletionItemKind.Class, + 'traceback': lsp.CompletionItemKind.Class, + 'frame': lsp.CompletionItemKind.Class, + 'buffer': lsp.CompletionItemKind.Class, + 'dictproxy': lsp.CompletionItemKind.Class, + 'funcdef': lsp.CompletionItemKind.Function, + 'property': lsp.CompletionItemKind.Property, + 'import': lsp.CompletionItemKind.Module, + 'keyword': lsp.CompletionItemKind.Keyword, + 'constant': lsp.CompletionItemKind.Variable, + 'variable': lsp.CompletionItemKind.Variable, + 'value': lsp.CompletionItemKind.Value, + 'param': lsp.CompletionItemKind.Variable, + 'statement': lsp.CompletionItemKind.Keyword, + } + + return MAP.get(d.type) diff --git a/external-deps/python-language-server/pyls/plugins/rope_rename.py b/external-deps/python-language-server/pyls/plugins/rope_rename.py new file mode 100644 index 00000000000..80091c0df39 --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/rope_rename.py @@ -0,0 +1,54 @@ +# Copyright 2017 Palantir Technologies, Inc. +import logging +import os + +from rope.base import libutils +from rope.refactor.rename import Rename + +from pyls import hookimpl, uris + +log = logging.getLogger(__name__) + + +@hookimpl +def pyls_settings(): + # Default rope_rename to disabled + return {'plugins': {'rope_rename': {'enabled': False}}} + + +@hookimpl +def pyls_rename(config, workspace, document, position, new_name): + rope_config = config.settings(document_path=document.path).get('rope', {}) + rope_project = workspace._rope_project_builder(rope_config) + + rename = Rename( + rope_project, + libutils.path_to_resource(rope_project, document.path), + document.offset_at_position(position) + ) + + log.debug("Executing rename of %s to %s", document.word_at_position(position), new_name) + changeset = rename.get_changes(new_name, in_hierarchy=True, docs=True) + log.debug("Finished rename: %s", changeset.changes) + return { + 'documentChanges': [{ + 'textDocument': { + 'uri': uris.uri_with( + document.uri, path=os.path.join(workspace.root_path, change.resource.path) + ), + 'version': workspace.get_document(document.uri).version + }, + 'edits': [{ + 'range': { + 'start': {'line': 0, 'character': 0}, + 'end': {'line': _num_lines(change.resource), 'character': 0}, + }, + 'newText': change.new_contents + }] + } for change in changeset.changes] + } + + +def _num_lines(resource): + "Count the number of lines in a `File` resource." + return len(resource.read().splitlines()) diff --git a/external-deps/python-language-server/pyls/plugins/signature.py b/external-deps/python-language-server/pyls/plugins/signature.py new file mode 100644 index 00000000000..fff7a5760ac --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/signature.py @@ -0,0 +1,58 @@ +# Copyright 2017 Palantir Technologies, Inc. +import logging +import re +from pyls import hookimpl, _utils + +log = logging.getLogger(__name__) + +SPHINX = re.compile(r"\s*:param\s+(?P\w+):\s*(?P[^\n]+)") +EPYDOC = re.compile(r"\s*@param\s+(?P\w+):\s*(?P[^\n]+)") +GOOGLE = re.compile(r"\s*(?P\w+).*:\s*(?P[^\n]+)") + +DOC_REGEX = [SPHINX, EPYDOC, GOOGLE] + + +@hookimpl +def pyls_signature_help(document, position): + code_position = _utils.position_to_jedi_linecolumn(document, position) + signatures = document.jedi_script().get_signatures(**code_position) + + if not signatures: + return {'signatures': []} + + s = signatures[0] + + # 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 = ' '.join([line.strip() for line in function_sig_lines]) + sig = { + 'label': function_sig, + 'documentation': _utils.format_docstring(s.docstring(raw=True)) + } + + # If there are params, add those + if s.params: + sig['parameters'] = [{ + 'label': p.name, + 'documentation': _param_docs(s.docstring(), p.name) + } for p in s.params] + + # We only return a single signature because Python doesn't allow overloading + sig_info = {'signatures': [sig], 'activeSignature': 0} + + if s.index is not None and s.params: + # Then we know which parameter we're looking at + sig_info['activeParameter'] = s.index + + return sig_info + + +def _param_docs(docstring, param_name): + for line in docstring.splitlines(): + for regex in DOC_REGEX: + m = regex.match(line) + if not m: + continue + if m.group('param') != param_name: + continue + return m.group('doc') or "" diff --git a/external-deps/python-language-server/pyls/plugins/symbols.py b/external-deps/python-language-server/pyls/plugins/symbols.py new file mode 100644 index 00000000000..ced9721893b --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/symbols.py @@ -0,0 +1,103 @@ +# Copyright 2017 Palantir Technologies, Inc. +import logging +from pyls import hookimpl +from pyls.lsp import SymbolKind + +log = logging.getLogger(__name__) + + +@hookimpl +def pyls_document_symbols(config, document): + all_scopes = config.plugin_settings('jedi_symbols').get('all_scopes', True) + definitions = document.jedi_names(all_scopes=all_scopes) + return [{ + 'name': d.name, + 'containerName': _container(d), + 'location': { + 'uri': document.uri, + 'range': _range(d), + }, + 'kind': _kind(d), + } for d in definitions if _include_def(d)] + + +def _include_def(definition): + return ( + # Don't tend to include parameters as symbols + definition.type != 'param' and + # Unused vars should also be skipped + definition.name != '_' and + _kind(definition) is not None + ) + + +def _container(definition): + try: + # Jedi sometimes fails here. + parent = definition.parent() + # Here we check that a grand-parent exists to avoid declaring symbols + # as children of the module. + if parent.parent(): + return parent.name + except: # pylint: disable=bare-except + return None + + return None + + +def _range(definition): + # This gets us more accurate end position + definition = definition._name.tree_name.get_definition() + (start_line, start_column) = definition.start_pos + (end_line, end_column) = definition.end_pos + return { + 'start': {'line': start_line - 1, 'character': start_column}, + 'end': {'line': end_line - 1, 'character': end_column} + } + + +_SYMBOL_KIND_MAP = { + 'none': SymbolKind.Variable, + 'type': SymbolKind.Class, + 'tuple': SymbolKind.Class, + 'dict': SymbolKind.Class, + 'dictionary': SymbolKind.Class, + 'function': SymbolKind.Function, + 'lambda': SymbolKind.Function, + 'generator': SymbolKind.Function, + 'class': SymbolKind.Class, + 'instance': SymbolKind.Class, + 'method': SymbolKind.Method, + 'builtin': SymbolKind.Class, + 'builtinfunction': SymbolKind.Function, + 'module': SymbolKind.Module, + 'file': SymbolKind.File, + 'xrange': SymbolKind.Array, + 'slice': SymbolKind.Class, + 'traceback': SymbolKind.Class, + 'frame': SymbolKind.Class, + 'buffer': SymbolKind.Array, + 'dictproxy': SymbolKind.Class, + 'funcdef': SymbolKind.Function, + 'property': SymbolKind.Property, + 'import': SymbolKind.Module, + 'keyword': SymbolKind.Variable, + 'constant': SymbolKind.Constant, + 'variable': SymbolKind.Variable, + 'value': SymbolKind.Variable, + 'param': SymbolKind.Variable, + 'statement': SymbolKind.Variable, + 'boolean': SymbolKind.Boolean, + 'int': SymbolKind.Number, + 'longlean': SymbolKind.Number, + 'float': SymbolKind.Number, + 'complex': SymbolKind.Number, + 'string': SymbolKind.String, + 'unicode': SymbolKind.String, + 'list': SymbolKind.Array, +} + + +def _kind(d): + """ Return the VSCode Symbol Type """ + return _SYMBOL_KIND_MAP.get(d.type) diff --git a/external-deps/python-language-server/pyls/plugins/yapf_format.py b/external-deps/python-language-server/pyls/plugins/yapf_format.py new file mode 100644 index 00000000000..16afe97dc18 --- /dev/null +++ b/external-deps/python-language-server/pyls/plugins/yapf_format.py @@ -0,0 +1,56 @@ +# Copyright 2017 Palantir Technologies, Inc. +import logging +import os +from yapf.yapflib import file_resources +from yapf.yapflib.yapf_api import FormatCode +from pyls import hookimpl + +log = logging.getLogger(__name__) + + +@hookimpl +def pyls_format_document(document): + return _format(document) + + +@hookimpl +def pyls_format_range(document, range): # pylint: disable=redefined-builtin + # First we 'round' the range up/down to full lines only + range['start']['character'] = 0 + range['end']['line'] += 1 + range['end']['character'] = 0 + + # From Yapf docs: + # lines: (list of tuples of integers) A list of tuples of lines, [start, end], + # that we want to format. The lines are 1-based indexed. It can be used by + # third-party code (e.g., IDEs) when reformatting a snippet of code rather + # than a whole file. + + # Add 1 for 1-indexing vs LSP's 0-indexing + lines = [(range['start']['line'] + 1, range['end']['line'] + 1)] + return _format(document, lines=lines) + + +def _format(document, lines=None): + new_source, changed = FormatCode( + document.source, + lines=lines, + filename=document.filename, + style_config=file_resources.GetDefaultStyleForDir( + os.path.dirname(document.path) + ) + ) + + if not changed: + return [] + + # I'm too lazy at the moment to parse diffs into TextEdit items + # So let's just return the entire file... + return [{ + 'range': { + 'start': {'line': 0, 'character': 0}, + # End char 0 of the line after our document + 'end': {'line': len(document.lines), 'character': 0} + }, + 'newText': new_source + }] diff --git a/external-deps/python-language-server/pyls/python_ls.py b/external-deps/python-language-server/pyls/python_ls.py new file mode 100644 index 00000000000..8d6c5f0d7f9 --- /dev/null +++ b/external-deps/python-language-server/pyls/python_ls.py @@ -0,0 +1,435 @@ +# Copyright 2017 Palantir Technologies, Inc. +from functools import partial +import logging +import os +import socketserver +import threading + +from pyls_jsonrpc.dispatchers import MethodDispatcher +from pyls_jsonrpc.endpoint import Endpoint +from pyls_jsonrpc.streams import JsonRpcStreamReader, JsonRpcStreamWriter + +from . import lsp, _utils, uris +from .config import config +from .workspace import Workspace + +log = logging.getLogger(__name__) + + +LINT_DEBOUNCE_S = 0.5 # 500 ms +PARENT_PROCESS_WATCH_INTERVAL = 10 # 10 s +MAX_WORKERS = 64 +PYTHON_FILE_EXTENSIONS = ('.py', '.pyi') +CONFIG_FILEs = ('pycodestyle.cfg', 'setup.cfg', 'tox.ini', '.flake8') + + +class _StreamHandlerWrapper(socketserver.StreamRequestHandler, object): + """A wrapper class that is used to construct a custom handler class.""" + + delegate = None + + def setup(self): + super(_StreamHandlerWrapper, self).setup() + # pylint: disable=no-member + self.delegate = self.DELEGATE_CLASS(self.rfile, self.wfile) + + def handle(self): + try: + self.delegate.start() + except OSError as e: + if os.name == 'nt': + # Catch and pass on ConnectionResetError when parent process + # dies + # pylint: disable=no-member, undefined-variable + if isinstance(e, WindowsError) and e.winerror == 10054: + pass + + # pylint: disable=no-member + self.SHUTDOWN_CALL() + + +def start_tcp_lang_server(bind_addr, port, check_parent_process, handler_class): + if not issubclass(handler_class, PythonLanguageServer): + raise ValueError('Handler class must be an instance of PythonLanguageServer') + + def shutdown_server(*args): + # pylint: disable=unused-argument + log.debug('Shutting down server') + # Shutdown call must be done on a thread, to prevent deadlocks + stop_thread = threading.Thread(target=server.shutdown) + stop_thread.start() + + # Construct a custom wrapper class around the user's handler_class + wrapper_class = type( + handler_class.__name__ + 'Handler', + (_StreamHandlerWrapper,), + {'DELEGATE_CLASS': partial(handler_class, + check_parent_process=check_parent_process), + 'SHUTDOWN_CALL': shutdown_server} + ) + + server = socketserver.TCPServer((bind_addr, port), wrapper_class, bind_and_activate=False) + server.allow_reuse_address = True + + try: + server.server_bind() + server.server_activate() + log.info('Serving %s on (%s, %s)', handler_class.__name__, bind_addr, port) + server.serve_forever() + finally: + log.info('Shutting down') + server.server_close() + + +def start_io_lang_server(rfile, wfile, check_parent_process, handler_class): + if not issubclass(handler_class, PythonLanguageServer): + raise ValueError('Handler class must be an instance of PythonLanguageServer') + log.info('Starting %s IO language server', handler_class.__name__) + server = handler_class(rfile, wfile, check_parent_process) + server.start() + + +class PythonLanguageServer(MethodDispatcher): + """ Implementation of the Microsoft VSCode Language Server Protocol + https://github.com/Microsoft/language-server-protocol/blob/master/versions/protocol-1-x.md + """ + + # pylint: disable=too-many-public-methods,redefined-builtin + + def __init__(self, rx, tx, check_parent_process=False): + self.workspace = None + self.config = None + self.root_uri = None + self.watching_thread = None + self.workspaces = {} + self.uri_workspace_mapper = {} + + self._jsonrpc_stream_reader = JsonRpcStreamReader(rx) + self._jsonrpc_stream_writer = JsonRpcStreamWriter(tx) + self._check_parent_process = check_parent_process + self._endpoint = Endpoint(self, self._jsonrpc_stream_writer.write, max_workers=MAX_WORKERS) + self._dispatchers = [] + self._shutdown = False + + def start(self): + """Entry point for the server.""" + self._jsonrpc_stream_reader.listen(self._endpoint.consume) + + def __getitem__(self, item): + """Override getitem to fallback through multiple dispatchers.""" + if self._shutdown and item != 'exit': + # exit is the only allowed method during shutdown + log.debug("Ignoring non-exit method during shutdown: %s", item) + raise KeyError + + try: + return super(PythonLanguageServer, self).__getitem__(item) + except KeyError: + # Fallback through extra dispatchers + for dispatcher in self._dispatchers: + try: + return dispatcher[item] + except KeyError: + continue + + raise KeyError() + + def m_shutdown(self, **_kwargs): + self._shutdown = True + return None + + def m_exit(self, **_kwargs): + self._endpoint.shutdown() + self._jsonrpc_stream_reader.close() + self._jsonrpc_stream_writer.close() + + def _match_uri_to_workspace(self, uri): + workspace_uri = _utils.match_uri_to_workspace(uri, self.workspaces) + return self.workspaces.get(workspace_uri, self.workspace) + + def _hook(self, hook_name, doc_uri=None, **kwargs): + """Calls hook_name and returns a list of results from all registered handlers""" + workspace = self._match_uri_to_workspace(doc_uri) + doc = workspace.get_document(doc_uri) if doc_uri else None + hook_handlers = self.config.plugin_manager.subset_hook_caller(hook_name, self.config.disabled_plugins) + return hook_handlers(config=self.config, workspace=workspace, document=doc, **kwargs) + + def capabilities(self): + server_capabilities = { + 'codeActionProvider': True, + 'codeLensProvider': { + 'resolveProvider': False, # We may need to make this configurable + }, + 'completionProvider': { + 'resolveProvider': False, # We know everything ahead of time + 'triggerCharacters': ['.'] + }, + 'documentFormattingProvider': True, + 'documentHighlightProvider': True, + 'documentRangeFormattingProvider': True, + 'documentSymbolProvider': True, + 'definitionProvider': True, + 'executeCommandProvider': { + 'commands': flatten(self._hook('pyls_commands')) + }, + 'hoverProvider': True, + 'referencesProvider': True, + 'renameProvider': True, + 'foldingRangeProvider': True, + 'signatureHelpProvider': { + 'triggerCharacters': ['(', ',', '='] + }, + 'textDocumentSync': { + 'change': lsp.TextDocumentSyncKind.INCREMENTAL, + 'save': { + 'includeText': True, + }, + 'openClose': True, + }, + 'workspace': { + 'workspaceFolders': { + 'supported': True, + 'changeNotifications': True + } + }, + 'experimental': merge(self._hook('pyls_experimental_capabilities')) + } + log.info('Server capabilities: %s', server_capabilities) + return server_capabilities + + def m_initialize(self, processId=None, rootUri=None, rootPath=None, initializationOptions=None, **_kwargs): + log.debug('Language server initialized with %s %s %s %s', processId, rootUri, rootPath, initializationOptions) + if rootUri is None: + rootUri = uris.from_fs_path(rootPath) if rootPath is not None else '' + + self.workspaces.pop(self.root_uri, None) + self.root_uri = rootUri + self.config = config.Config(rootUri, initializationOptions or {}, + processId, _kwargs.get('capabilities', {})) + self.workspace = Workspace(rootUri, self._endpoint, self.config) + self.workspaces[rootUri] = self.workspace + self._dispatchers = self._hook('pyls_dispatchers') + self._hook('pyls_initialize') + + if self._check_parent_process and processId is not None and self.watching_thread is None: + def watch_parent_process(pid): + # exit when the given pid is not alive + if not _utils.is_process_alive(pid): + log.info("parent process %s is not alive, exiting!", pid) + self.m_exit() + else: + threading.Timer(PARENT_PROCESS_WATCH_INTERVAL, watch_parent_process, args=[pid]).start() + + self.watching_thread = threading.Thread(target=watch_parent_process, args=(processId,)) + self.watching_thread.daemon = True + self.watching_thread.start() + # Get our capabilities + return {'capabilities': self.capabilities()} + + def m_initialized(self, **_kwargs): + self._hook('pyls_initialized') + + def code_actions(self, doc_uri, range, context): + return flatten(self._hook('pyls_code_actions', doc_uri, range=range, context=context)) + + def code_lens(self, doc_uri): + return flatten(self._hook('pyls_code_lens', doc_uri)) + + def completions(self, doc_uri, position): + completions = self._hook('pyls_completions', doc_uri, position=position) + return { + 'isIncomplete': False, + 'items': flatten(completions) + } + + def definitions(self, doc_uri, position): + return flatten(self._hook('pyls_definitions', doc_uri, position=position)) + + def document_symbols(self, doc_uri): + return flatten(self._hook('pyls_document_symbols', doc_uri)) + + def execute_command(self, command, arguments): + return self._hook('pyls_execute_command', command=command, arguments=arguments) + + def format_document(self, doc_uri): + return self._hook('pyls_format_document', doc_uri) + + def format_range(self, doc_uri, range): + return self._hook('pyls_format_range', doc_uri, range=range) + + def highlight(self, doc_uri, position): + return flatten(self._hook('pyls_document_highlight', doc_uri, position=position)) or None + + def hover(self, doc_uri, position): + return self._hook('pyls_hover', doc_uri, position=position) or {'contents': ''} + + @_utils.debounce(LINT_DEBOUNCE_S, keyed_by='doc_uri') + def lint(self, doc_uri, is_saved): + # Since we're debounced, the document may no longer be open + workspace = self._match_uri_to_workspace(doc_uri) + if doc_uri in workspace.documents: + workspace.publish_diagnostics( + doc_uri, + flatten(self._hook('pyls_lint', doc_uri, is_saved=is_saved)) + ) + + def references(self, doc_uri, position, exclude_declaration): + return flatten(self._hook( + 'pyls_references', doc_uri, position=position, + exclude_declaration=exclude_declaration + )) + + def rename(self, doc_uri, position, new_name): + return self._hook('pyls_rename', doc_uri, position=position, new_name=new_name) + + def signature_help(self, doc_uri, position): + return self._hook('pyls_signature_help', doc_uri, position=position) + + def folding(self, doc_uri): + return self._hook('pyls_folding_range', doc_uri) + + def m_text_document__did_close(self, textDocument=None, **_kwargs): + workspace = self._match_uri_to_workspace(textDocument['uri']) + workspace.rm_document(textDocument['uri']) + + def m_text_document__did_open(self, textDocument=None, **_kwargs): + workspace = self._match_uri_to_workspace(textDocument['uri']) + workspace.put_document(textDocument['uri'], textDocument['text'], version=textDocument.get('version')) + self._hook('pyls_document_did_open', textDocument['uri']) + self.lint(textDocument['uri'], is_saved=True) + + def m_text_document__did_change(self, contentChanges=None, textDocument=None, **_kwargs): + workspace = self._match_uri_to_workspace(textDocument['uri']) + for change in contentChanges: + workspace.update_document( + textDocument['uri'], + change, + version=textDocument.get('version') + ) + self.lint(textDocument['uri'], is_saved=False) + + def m_text_document__did_save(self, textDocument=None, **_kwargs): + self.lint(textDocument['uri'], is_saved=True) + + def m_text_document__code_action(self, textDocument=None, range=None, context=None, **_kwargs): + return self.code_actions(textDocument['uri'], range, context) + + def m_text_document__code_lens(self, textDocument=None, **_kwargs): + return self.code_lens(textDocument['uri']) + + def m_text_document__completion(self, textDocument=None, position=None, **_kwargs): + return self.completions(textDocument['uri'], position) + + def m_text_document__definition(self, textDocument=None, position=None, **_kwargs): + return self.definitions(textDocument['uri'], position) + + def m_text_document__document_highlight(self, textDocument=None, position=None, **_kwargs): + return self.highlight(textDocument['uri'], position) + + def m_text_document__hover(self, textDocument=None, position=None, **_kwargs): + return self.hover(textDocument['uri'], position) + + def m_text_document__document_symbol(self, textDocument=None, **_kwargs): + return self.document_symbols(textDocument['uri']) + + def m_text_document__formatting(self, textDocument=None, _options=None, **_kwargs): + # For now we're ignoring formatting options. + return self.format_document(textDocument['uri']) + + def m_text_document__rename(self, textDocument=None, position=None, newName=None, **_kwargs): + return self.rename(textDocument['uri'], position, newName) + + def m_text_document__folding_range(self, textDocument=None, **_kwargs): + return self.folding(textDocument['uri']) + + def m_text_document__range_formatting(self, textDocument=None, range=None, _options=None, **_kwargs): + # Again, we'll ignore formatting options for now. + return self.format_range(textDocument['uri'], range) + + def m_text_document__references(self, textDocument=None, position=None, context=None, **_kwargs): + exclude_declaration = not context['includeDeclaration'] + return self.references(textDocument['uri'], position, exclude_declaration) + + def m_text_document__signature_help(self, textDocument=None, position=None, **_kwargs): + return self.signature_help(textDocument['uri'], position) + + def m_workspace__did_change_configuration(self, settings=None): + self.config.update((settings or {}).get('pyls', {})) + for workspace_uri in self.workspaces: + workspace = self.workspaces[workspace_uri] + workspace.update_config(self.config) + for doc_uri in workspace.documents: + self.lint(doc_uri, is_saved=False) + + def m_workspace__did_change_workspace_folders(self, event=None, **_kwargs): # pylint: disable=too-many-locals + if event is None: + return + added = event.get('added', []) + removed = event.get('removed', []) + + for removed_info in removed: + if 'uri' in removed_info: + removed_uri = removed_info['uri'] + self.workspaces.pop(removed_uri, None) + + for added_info in added: + if 'uri' in added_info: + added_uri = added_info['uri'] + self.workspaces[added_uri] = Workspace(added_uri, self._endpoint, self.config) + + root_workspace_removed = any(removed_info['uri'] == self.root_uri for removed_info in removed) + workspace_added = len(added) > 0 and 'uri' in added[0] + if root_workspace_removed and workspace_added: + added_uri = added[0]['uri'] + self.root_uri = added_uri + self.workspace = self.workspaces[added_uri] + elif root_workspace_removed: + # NOTE: Removing the root workspace can only happen when the server + # is closed, thus the else condition of this if can never happen. + if self.workspaces: + log.debug('Root workspace deleted!') + available_workspaces = sorted(self.workspaces) + first_workspace = available_workspaces[0] + self.root_uri = first_workspace + self.workspace = self.workspaces[first_workspace] + + # Migrate documents that are on the root workspace and have a better + # match now + doc_uris = list(self.workspace._docs.keys()) + for uri in doc_uris: + doc = self.workspace._docs.pop(uri) + new_workspace = self._match_uri_to_workspace(uri) + new_workspace._docs[uri] = doc + + def m_workspace__did_change_watched_files(self, changes=None, **_kwargs): + changed_py_files = set() + config_changed = False + for d in (changes or []): + if d['uri'].endswith(PYTHON_FILE_EXTENSIONS): + changed_py_files.add(d['uri']) + elif d['uri'].endswith(CONFIG_FILEs): + config_changed = True + + if config_changed: + self.config.settings.cache_clear() + elif not changed_py_files: + # Only externally changed python files and lint configs may result in changed diagnostics. + return + + for workspace_uri in self.workspaces: + workspace = self.workspaces[workspace_uri] + for doc_uri in workspace.documents: + # Changes in doc_uri are already handled by m_text_document__did_save + if doc_uri not in changed_py_files: + self.lint(doc_uri, is_saved=False) + + def m_workspace__execute_command(self, command=None, arguments=None): + return self.execute_command(command, arguments) + + +def flatten(list_of_lists): + return [item for lst in list_of_lists for item in lst] + + +def merge(list_of_dicts): + return {k: v for dictionary in list_of_dicts for k, v in dictionary.items()} diff --git a/external-deps/python-language-server/pyls/uris.py b/external-deps/python-language-server/pyls/uris.py new file mode 100644 index 00000000000..7299ac9f654 --- /dev/null +++ b/external-deps/python-language-server/pyls/uris.py @@ -0,0 +1,129 @@ +# Copyright 2017 Palantir Technologies, Inc. +"""A collection of URI utilities with logic built on the VSCode URI library. + +https://github.com/Microsoft/vscode-uri/blob/e59cab84f5df6265aed18ae5f43552d3eef13bb9/lib/index.ts +""" +import re +from urllib import parse +from pyls import IS_WIN + +RE_DRIVE_LETTER_PATH = re.compile(r'^\/[a-zA-Z]:') + + +def urlparse(uri): + """Parse and decode the parts of a URI.""" + scheme, netloc, path, params, query, fragment = parse.urlparse(uri) + return ( + parse.unquote(scheme), + parse.unquote(netloc), + parse.unquote(path), + parse.unquote(params), + parse.unquote(query), + parse.unquote(fragment) + ) + + +def urlunparse(parts): + """Unparse and encode parts of a URI.""" + scheme, netloc, path, params, query, fragment = parts + + # Avoid encoding the windows drive letter colon + if RE_DRIVE_LETTER_PATH.match(path): + quoted_path = path[:3] + parse.quote(path[3:]) + else: + quoted_path = parse.quote(path) + + return parse.urlunparse(( + parse.quote(scheme), + parse.quote(netloc), + quoted_path, + parse.quote(params), + parse.quote(query), + parse.quote(fragment) + )) + + +def to_fs_path(uri): + """Returns the filesystem path of the given URI. + + Will handle UNC paths and normalize windows drive letters to lower-case. Also + uses the platform specific path separator. Will *not* validate the path for + invalid characters and semantics. Will *not* look at the scheme of this URI. + """ + # scheme://netloc/path;parameters?query#fragment + scheme, netloc, path, _params, _query, _fragment = urlparse(uri) + + if netloc and path and scheme == 'file': + # unc path: file://shares/c$/far/boo + value = "//{}{}".format(netloc, path) + + elif RE_DRIVE_LETTER_PATH.match(path): + # windows drive letter: file:///C:/far/boo + value = path[1].lower() + path[2:] + + else: + # Other path + value = path + + if IS_WIN: + value = value.replace('/', '\\') + + return value + + +def from_fs_path(path): + """Returns a URI for the given filesystem path.""" + scheme = 'file' + params, query, fragment = '', '', '' + path, netloc = _normalize_win_path(path) + return urlunparse((scheme, netloc, path, params, query, fragment)) + + +def uri_with(uri, scheme=None, netloc=None, path=None, params=None, query=None, fragment=None): + """Return a URI with the given part(s) replaced. + + Parts are decoded / encoded. + """ + old_scheme, old_netloc, old_path, old_params, old_query, old_fragment = urlparse(uri) + path, _netloc = _normalize_win_path(path) + return urlunparse(( + scheme or old_scheme, + netloc or old_netloc, + path or old_path, + params or old_params, + query or old_query, + fragment or old_fragment + )) + + +def _normalize_win_path(path): + netloc = '' + + # normalize to fwd-slashes on windows, + # on other systems bwd-slaches are valid + # filename character, eg /f\oo/ba\r.txt + if IS_WIN: + path = path.replace('\\', '/') + + # check for authority as used in UNC shares + # or use the path as given + if path[:2] == '//': + idx = path.index('/', 2) + if idx == -1: + netloc = path[2:] + else: + netloc = path[2:idx] + path = path[idx:] + else: + path = path + + # Ensure that path starts with a slash + # or that it is at least a slash + if not path.startswith('/'): + path = '/' + path + + # Normalize drive paths to lower case + if RE_DRIVE_LETTER_PATH.match(path): + path = path[0] + path[1].lower() + path[2:] + + return path, netloc diff --git a/external-deps/python-language-server/pyls/workspace.py b/external-deps/python-language-server/pyls/workspace.py new file mode 100644 index 00000000000..d89fe08b44e --- /dev/null +++ b/external-deps/python-language-server/pyls/workspace.py @@ -0,0 +1,264 @@ +# Copyright 2017 Palantir Technologies, Inc. +import io +import logging +import os +import re + +import jedi + +from . import lsp, uris, _utils + +log = logging.getLogger(__name__) + +# 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]*') + + +class Workspace(object): + + M_PUBLISH_DIAGNOSTICS = 'textDocument/publishDiagnostics' + M_APPLY_EDIT = 'workspace/applyEdit' + M_SHOW_MESSAGE = 'window/showMessage' + + def __init__(self, root_uri, endpoint, config=None): + self._config = config + self._root_uri = root_uri + self._endpoint = endpoint + self._root_uri_scheme = uris.urlparse(self._root_uri)[0] + self._root_path = uris.to_fs_path(self._root_uri) + self._docs = {} + + # Cache jedi environments + self._environments = {} + + # Whilst incubating, keep rope private + self.__rope = None + self.__rope_config = None + + def _rope_project_builder(self, rope_config): + from rope.base.project import Project + + # TODO: we could keep track of dirty files and validate only those + if self.__rope is None or self.__rope_config != rope_config: + rope_folder = rope_config.get('ropeFolder') + self.__rope = Project(self._root_path, ropefolder=rope_folder) + self.__rope.prefs.set('extension_modules', rope_config.get('extensionModules', [])) + self.__rope.prefs.set('ignore_syntax_errors', True) + self.__rope.prefs.set('ignore_bad_imports', True) + self.__rope.validate() + return self.__rope + + @property + def documents(self): + return self._docs + + @property + def root_path(self): + return self._root_path + + @property + def root_uri(self): + return self._root_uri + + def is_local(self): + return (self._root_uri_scheme == '' or self._root_uri_scheme == 'file') and os.path.exists(self._root_path) + + def get_document(self, doc_uri): + """Return a managed document if-present, else create one pointing at disk. + + See https://github.com/Microsoft/language-server-protocol/issues/177 + """ + return self._docs.get(doc_uri) or self._create_document(doc_uri) + + def put_document(self, doc_uri, source, version=None): + self._docs[doc_uri] = self._create_document(doc_uri, source=source, version=version) + + def rm_document(self, doc_uri): + self._docs.pop(doc_uri) + + def update_document(self, doc_uri, change, version=None): + self._docs[doc_uri].apply_change(change) + self._docs[doc_uri].version = version + + def update_config(self, config): + self._config = config + for doc_uri in self.documents: + self.get_document(doc_uri).update_config(config) + + def apply_edit(self, edit): + return self._endpoint.request(self.M_APPLY_EDIT, {'edit': edit}) + + def publish_diagnostics(self, doc_uri, diagnostics): + self._endpoint.notify(self.M_PUBLISH_DIAGNOSTICS, params={'uri': doc_uri, 'diagnostics': diagnostics}) + + def show_message(self, message, msg_type=lsp.MessageType.Info): + self._endpoint.notify(self.M_SHOW_MESSAGE, params={'type': msg_type, 'message': message}) + + def source_roots(self, document_path): + """Return the source roots for the given document.""" + files = _utils.find_parents(self._root_path, document_path, ['setup.py', 'pyproject.toml']) or [] + return list(set((os.path.dirname(project_file) for project_file in files))) or [self._root_path] + + def _create_document(self, doc_uri, source=None, version=None): + path = uris.to_fs_path(doc_uri) + return Document( + doc_uri, self, source=source, version=version, + extra_sys_path=self.source_roots(path), + rope_project_builder=self._rope_project_builder, + config=self._config, + ) + + +class Document(object): + + 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) + self.filename = os.path.basename(self.path) + + self._config = config + self._workspace = workspace + self._local = local + self._source = source + self._extra_sys_path = extra_sys_path or [] + self._rope_project_builder = rope_project_builder + + def __str__(self): + return str(self.uri) + + def _rope_resource(self, rope_config): + from rope.base import libutils + return libutils.path_to_resource(self._rope_project_builder(rope_config), self.path) + + @property + def lines(self): + return self.source.splitlines(True) + + @property + def source(self): + if self._source is None: + with io.open(self.path, 'r', encoding='utf-8') as f: + return f.read() + return self._source + + def update_config(self, config): + self._config = config + + def apply_change(self, change): + """Apply a change to the document.""" + text = change['text'] + change_range = change.get('range') + + if not change_range: + # The whole file has changed + self._source = text + return + + start_line = change_range['start']['line'] + start_col = change_range['start']['character'] + end_line = change_range['end']['line'] + end_col = change_range['end']['character'] + + # Check for an edit occuring at the very end of the file + if start_line == len(self.lines): + self._source = self.source + text + return + + new = io.StringIO() + + # Iterate over the existing document until we hit the edit range, + # at which point we write the new text, then loop until we hit + # the end of the range and continue writing. + for i, line in enumerate(self.lines): + if i < start_line: + new.write(line) + continue + + if i > end_line: + new.write(line) + continue + + if i == start_line: + new.write(line[:start_col]) + new.write(text) + + if i == end_line: + new.write(line[end_col:]) + + self._source = new.getvalue() + + def offset_at_position(self, position): + """Return the byte-offset pointed at by the given position.""" + return position['character'] + len(''.join(self.lines[:position['line']])) + + def word_at_position(self, position): + """Get the word under the cursor returning the start and end positions.""" + if position['line'] >= len(self.lines): + return '' + + line = self.lines[position['line']] + i = position['character'] + # Split word in two + start = line[:i] + end = line[i:] + + # Take end of start and start of end to find word + # These are guaranteed to match, even if they match the empty string + m_start = RE_START_WORD.findall(start) + m_end = RE_END_WORD.findall(end) + + return m_start[0] + m_end[-1] + + def jedi_names(self, all_scopes=False, definitions=True, references=False): + script = self.jedi_script() + return script.get_names(all_scopes=all_scopes, definitions=definitions, + references=references) + + def jedi_script(self, position=None): + extra_paths = [] + environment_path = None + + if self._config: + jedi_settings = self._config.plugin_settings('jedi', document_path=self.path) + environment_path = jedi_settings.get('environment') + extra_paths = jedi_settings.get('extra_paths') or [] + + environment = self.get_enviroment(environment_path) if environment_path else None + sys_path = self.sys_path(environment_path) + extra_paths + project_path = self._workspace.root_path + + kwargs = { + 'code': self.source, + 'path': self.path, + 'environment': environment, + 'project': jedi.Project(path=project_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): + # TODO(gatesn): #339 - make better use of jedi environments, they seem pretty powerful + if environment_path is None: + environment = jedi.api.environment.get_cached_default_environment() + else: + if environment_path in self._workspace._environments: + environment = self._workspace._environments[environment_path] + else: + environment = jedi.api.environment.create_environment(path=environment_path, safe=False) + self._workspace._environments[environment_path] = environment + + return environment + + def sys_path(self, environment_path=None): + # Copy our extra sys path + path = list(self._extra_sys_path) + environment = self.get_enviroment(environment_path=environment_path) + path.extend(environment.get_sys_path()) + return path diff --git a/external-deps/python-language-server/resources/auto-complete.gif b/external-deps/python-language-server/resources/auto-complete.gif new file mode 100644 index 0000000000000000000000000000000000000000..6c4fe4ff0603063f89ce6002525e7c90ee9da10e GIT binary patch literal 55532 zcmd4XcTf}GA2<4R5}E<&MS~5b8H#i;^bVni9;726Dnh7+-XYQv(9k=A^d72oBhrfo z5Tz=1EXd{i`~IGL@7(9P|2=o+o|)a9Is2KNv$K2NvpeUdt*a#`??eZ>2n+-O1Wp)? zG|kP_Rk50q;%G1saN6|~0yuMe6g}Ml|CGg@`=_CJgm})&o(Er)KX*;#JX#rb9(C!` zWsxf)LPA0puE~pvp)W~Xyogp1mAEbSsbH+4U39BMA=DLR#ik!Ls(f~MMdL`;Td)_c1Q@AP1OOS zehaF72d3)}GYaKU!}Dm~Jg4I#j4{5VZYikacokzJq-k?O&-JpQhmf)7Wvq{g>8(rV z_byrmU9bs5Tlh-hZcAGFUAMlYVCS!b4^UT-!rZu_F0H07uWPDeVx%f%sUu@&Ad5GY zxoa)=z(q+zLqk(jM_=F2$OvnRF~_M|+NxWdnVDN!;%sbe931c%r$BXQf{t5=zGoQL z`+<`--bMH3Ekn-$(|bV{0pYlin>U@^+&sLzZu$E9-MxD+BqWs1HWh9a4|hnXbIC{G zv*4};=bV$zxjj7RnZxf>i0~|-_pN5Q-^3W&!*{2Y&%c@{xQQpUL%==~g^xqsOkxV_ zH})o)_z*4qqHONPI0VK!5aRKH@y@}Cp5ZAE9uR><02i^BDPn{vdYn0FmN|8i`Qa*O z^e|`a7)QbsSJVJ|$}C&j;@O8QXR1}ekUs2`Vvikc~4FNUJ2z4z% zjUA!QJ>l)m@fsaT>cg3uFAKDzqN3yC;**k+h-r_~(nwJc^W(D~r>AG+GW^b9^9jO-bXq6`fUO-xM8%*-q=FK=#c?(Xg$d_4U6_3PiifB$)P|MxZc34jH_ zrPDy}kAj~Swi|6I8jL%Wg38rtEFMnclJZ&|Z7g}7hEh-D(|uMtmLX(TZ8tV^X($Kn zJYK-vST>a}cW-xftf}I~6J<|&e!XT7)dWn2u>E**)vF4uJWrusOSM|5Nt4&wcuUPf zspVke^~7&AOHCfHs@D`+>uhsf7sdQxqi4l{SNnsQ@8gQGkg2qO%OguL1lF^IZ7~gRy zq2zy<1R#&*Q^W>8-mO4{gSCx*$U^7Gdp_(jwG7ZNc6xq{J@{s^LK{pvIqxX(?XD0! zG3!f~fC7*7R-yn=>jQn}T`HODPi!Bk`N%D^2?hW%d+@9Edbbr`V;I(Y9fj12w^W~C zVoR0ts%(T2w+KyIFz`2vN!2&e>R34%3T1Tv73s@j1f6RIUUptuXgx*lT`re8JBY+9 zk4ZP%L{DYCN&#I+Z(qQ?jt3Kix#5V5YLde7DJcqWRa@EeCh*jlD~aVq5K2$NP~PiO z#}heFReKKG7T(Or!;B}BmdqIbeCu)OcWzUMx0NRS=sed?Z+NwC9*|G-2WtWP-p%yfbUYa5JVva84e z25nIZeP%0z{UI)Q?~Gx-^JSl&qq=7AJV(ZPKO4K45&C&t)G<@?`QGSoaj$qx_83WmaudlG$V&7)Xt$e=CVa>X}%-aPXd|SXT zRNY^6$?^HV7i+X>k>gtI)-*I{u?QC9wgf21F~KkeBd zpV3sXKwulkMZuT*nYdag>53p{N-9LG5rBuvy5<_G0NDJRQn)M&(lM;n7zb8X5>hC1 zkkbmQ?m<0FdF8UsYYhO%G(3b#{c#Q9nk27u3TA$^aAo`<?O&4vOn~-ZkNIk#<$X=YB~v<)|b$4to7|zore3M%HYz zn%X(85eX26=}qn|ruKO^gZP)nN0}=tl5r;h#(h)JUr~CHLDR%d!o^2`Q6igU-iufT z>Fc*IMsb4gLAA?26>&{@m~h!hU5Z}EaO2cVr1fUfN1{uv7*^@=CeCDael5H0ebvBS z&+K5Vxm<2)=e2M3tH-}GeUw~BHNy2~ixnmz&L$N0$2(jl3g4>kt5xGhrCG*Qzg6Sz zCz-FMM~LoA*5H{$3|p5C^b)_-dfbOw56@Ucmw&7C6C1UuGmW4Of2$`HidZ0Z<-31< zs|~(Rf1wP0rS0#x1}u}eN$0Og_i*+`(&g%#7xkCMd0d`lPkFmY)GST^%4&MdbYQD0 zvOE);)eIG>^|G2+p6~qL^0aV78n3^ye6sw#wSB72H*jL*^{?-36sCH=IQ`WPo*ylh z#|wADL{_#GesoY%>isM9*LH1wbjBFg_l-nfTYB`p3q4bR<-8)>hk)HYz@a!{fr0Cj z8swqDby35~6^`qeivm>rYZ6Nnj*aa<1fEt`TgRxqX*?|ErDM?vpIdnYGu!GzSBV6< z7Mlm(G^U^Ch4XYj1VR`uCWEhx#_l1A8oQc`MV`iAa3zj(U5i4J$yxwhzm$bKBeoGMGKbb5FFc3g7kr85ha9&QM!#{l90Pava@r#|ltoO{<{teG0= zf|`W>%+KQn#RO|Fzc~o_QM1mJ3v!>}b<;4+gnsaf>>H*5FoQg>V)e{c@J(mQ4tu%B??1B7*ef?c6Y0fUW7ah}q(_bF{=Igw2 zJL!)7^k)f{Fo2e^>PvRNulXl`cCcxkvlT|))?vrK*wN1Uw&`#6A;)|8GhK_%jlMt2 zKi>B+?pj`${@&VkeBhVXwYnDmtz9(&NO;lp`p5K--rvU`iD$ZLbjC*mynheljk`BE zUmT4n{{2KsQ`+2PZtK$j`#JYT_dD4aKc_?fej)!*+Ir*mlbZkcYo&3|uGNcQ^K{`~ zeMOF6U#3JaFZ9C6eG%vNXun?n{`-S+=I@Tv8=0j&e)du0UU6|`5bIafGhuJQf&|o` zUE7mii!c7ZPIw`+`96%39TjtOltp4#RqurqRBC*!czXQ3>*VBgir?Vj0~UVAd4CEg};Y$$eff(vlE^;|jh^kSVjG?>dZeJc6)dA(}|w zH3H#2DoP0rIztTHt_UXxhRNU%uVkT%Xhu&GOg%Sx9t#ZSj1kO@iIj_v&L!A-$Yi%Y zaMp>XZ(z_r0mN3KfC;kTyu+vh8rU~CJV-DsS13#g4>QFv7H>1?<}!w~!Dg}X)$NJ3 zLWDS+Ou}NMXf6Y10|SW;s6eKJ=O*}#5({W_j8yomKq%W#;2@TRi8N|mJxrO^=^k{Gd|ddoAtT$HJLm3B@=r+4y`UUIP}=>xoY18l>+S3i z=bUi)+~}Vn#41@qoe(Y0@W&M)-Eo1Y*sK`&yr7`mpnH*H6`_-KLDO_$q3;uda$sw! zd8P6>*$J|O@bEu6;mJFM+wI}Aae>&w=rZg4TS1R-?*o6xru<%b6!ZQ8K!^zOAi^t& zz1zfnPUtfzQ_up#7@BDj%@paGKPw;K?im=K6DcB;)T>L7kc+xbh+;VDh*Ca^Qq>95 ze#a1&8?EgDTR6;|<9;$lD9p+Ubb!Zpp<-P;V%Oveo{R8XN9j+w;|kDm`*DGu4UZYo zjPvM+pMR456O0?%<29-AX-6>+LxDr{b)Eh z5^BN)4Qwk>{8fVEiB#nYQGdknTPXbR5dru!Dj!24xRdB|Nen>$vYZDq|m8o?#TS`95 z5b-3xB09S>Q+TQJu~%@$JFQn8feuSS+<1`7kE&|=;G$)%lFsS|o}9X1ji)>{t$Nu_ zUK%aIHQn@?9X1+W%QXWw5BsWB`xRJ#1TRx%!~%Z9seKRVwTNVX>E1wr2`JdJg)U(R@RRPkW%SN;hn z5sV|!G6b2j|6_bl7j6dtt6(;;{Yl#*^(#C z@OQH@Z_CfcGI716lSM*%Wl|2Z8RAv)sv^^(s=0?!z=%pDSton!HG9=Ov=>hK>0Y{! zo3bL;w$@&{p_BS9K6Mw)bOj&n35Z!lL#-R43GTpGXDcK0o1zpm?SGXWAGIdQmV>QH zbXDcRm2w=aF>pK11l2f?W>Ox1R>0fIq1b7g5ExWlA@DO$(Ua%Faz*5F`n8{dvDJa> zRPJDRpy^>&SYSq2b)~#+PxtSt-lXh@yS14o)q#2)Rmg;@BF?P0imK@yJ&%`rZdVb? z=(Alod-rWCKJey#%kMh~?2E7J`x_GWCnWDgk0|>kBhbX`!1iK?zd0Sg17+87JUeXw-@=VJigEgFh zEetai4-_+HcCH$*TMp!#C=9k5^e5BhQB$&sLpfBqKLwCYL8yfekhxqK9|0NBz4RK1 zjHt$LJgkTO9Je1#PrJ2&@@PMKH24D%`^!3ZPY(ou!=+IfjL1Q$Nx+p!#AQ5KaFQIv z6?48aleH>vo>~&~CuHPKZMDz{X}q`t(~|1Z^1&-16O|z$L`Se1d=xrBy_i^B8KI|} zALP!YlRHkS81~v3Uwhu#1TTrO0*4ca_<5pa7AN34DKh(QSv;-7cH^V_A>(%0lLilB zY)dP<0+D`*do-~8Vv$5B;yy9Ke-X~m5y9dKG;4q>2erQ8o9>gHP7*CDn@Dr|6}ab} zkb%m$Odcwr&@uXf-;9>aOaeN23xoGx5Zsw)jMO?os#9_W|JCkDSp2$c;1hH z;jZ$6zx{%vGI$FB4(M6%oSJt5LoE(~kz$LX_KUG$i}8i0d+;)vc?k(lfl|sNYahCT zLs;(#)9S#%tOj7|rTy!7VXqyTz$I&QC?umA@wKh;nuFPzaoF0=T}Ti2oG%JNw+-iQ z06jcRNe3VZ4M0%j9E6OtWaXQ3`kt#dvlWaTvDFmAa~kq$iW%#)a?%Bz->( zA!=)oHU&Nbq7LV*&tV)B`3HHymiQ4u=f=hlsa5 zz$Zw0S^V5JGF<2{Lg_C;wHJs+(%)zRs=wa&XgK$I?Rv8hfC2eVs4|k@HXM7rlJ7@H zKq2@VKxs%s0RWMTr{g_@7a$So4KzgxbO8%jPGy?GK>CSH!G-Iw;oFHP{2(;DBG`evAcunV)1Ws1YbZZ>jsv{^5X4K`RHH&a^Z+Hun~DwFycB3* zFSwAhYE-znXEK&rffPO8BqXmKWbUsZ_DoWEN=rKg)dg=);nV{5Ws^@ zoC-9aTDwD=?VCb~P(chIX6Nzn2h8g?h)lMr+q=CV0uG=lzMCAWZ;|3V>Xc36wbwho z8|oD3pvrPF?R`Zrl$X5w-FH*E7aEOZ)IYc9Kn7VJK#P$OXd1ZRZ>xy*zD@-mqp~zv zAMb)IYDz9*M$QrN2_zKAXlm_s53rAaRqXt0Ui60tCx2fn5OjwoAgNC`O>S=}9wMF` z&cqVJ8Z1EN#~r`-fq-TB2YA4_RbD@^ES~8x5iCIa5q9P% zs_)O_jX41TIEuVc{uhB1{}^@+g7O0wqqizf9>dY(h4fVLHS*W=k6(F7;C?K8$#^G{ z_8LV3&pp`Hzdfhk07lWirM!8a@nII-0KEo43Md3EW3lFF0jMkrK&7s$$Fp2ED#g9r z&`jpOrgjx~DTmcmKxE&BOm*pJekfNLda0O}sGTpjwM0{MD>Zy1_m(o>^j`2WA`q`n znAtWd)y)!jU7p=Bt28MyDzj;+uE1MI9WT>7vHix59UjMD)z%mBWSQur%oed!rlNMP zf-ay>gBmY}?LrOO9Nn&q@H~L16&2xy=|50~z2XL^S<% zz3rD}U|PHC;OXa6(~U#)%J0C#_2D!@$Je3#0zT)p@2jjGha4emIKN{1{s#T|`R(KT zH*ZdK`Py-5JxBD?=+2*i&HPkhy#9y%^UI2UYV_Bm4%HZ?X8i`gT&g`(NAl{C)LHeV zKWVVBe@1I?oZ*wu9ZWSsn^VPEp`8<)_ zZsxcvnM~O~>8n&zGg6-7eTj9X6KB%r3nF6%olUaKkxuX0HF9;0>)Cj%OIiruVW*E^z&(`YSi*@NL^3#~GTlbH`T_*v1VW+NSJ`3Q z5H?q(zfMk{>RsopGex2-t5mZk-pQ#+$^?P0X#mTF?sOeqU@<{TFhbNceqM4$vaW+N zjeWT^GL7OlFR*n`6y_>V_~{XyBrZ0Vtrti}mSAOMx6!4C`Y`~_OsuSsi*v~bB?Y$P zvxsEULv^Q-3;{N$E1B5ahZ>n0leL{l6W{nCuv+)FMrOARjp(Nti~PFwZC)IncO%2J zoD^*v&iyHwu6*g87K3E|ok3)s{0@^j_N@#T!6>?&m*a^&)FDosIgf_HxH(>fA<8ni z=o9%5SNwEbzERi|93H-t<+`x36gRrJ5cxRO=IS-^HOiuD_!L3xsiMSe>5wu)6W*k1 zeLK!Ln3*}wu?yq2bSCm|^tznccSn_KKOlGi(KyAxvP$hxSm4PQcBy2ktBzNrkloAu zUD>Mf&bUNmNXgPk=~o%f%}c`!lZR}Nm0lw3eK1_C1#`~(tup$$AARBGyesB0f?S|= z`}-`hoHuC*H@;#o=GDm7NY!{?z#&%?FK$S|r0VIm7z<`U%i)scU?kr4ssk1#xqFip z$cl}5&dmj4-xhKs79;uWHYH$p7+ovzPQCXoN~QuqK65PGjn1(bcv|E$7>liZ_#l!b zlgo-6pHl$K=IwF-N*qP z3?6_{Qxj6>a=#giCXFV$hF!>PQgBrL_2UM<-r#Dn6dCpUTTCQm^DOV_$imo@BQJp- zDGI%Y`Jc3?b8~!5;l;#~l_VyR!in6mK&W)bRk(n64eI&f5R++p1pbn+81!niWJ7$W zV#*7yCzNvfoZ)NUBQxlop?-MOt07lk4BKM@r@%9u=J?CAIH<@dlb_$q*=^U97zKpH zSZ=)Y6{(^zHci!5N-}RPOTeVieB+1vyn)OS$O*LBJRTz%(=Fn&H1UdO>aCG@ce9gv zdq&aX+yoO`RpM!M=CXK}uF8F>q$aj?!8}!IH-CXbc^rej;e}))|NG+m!K#Ad-}D3~ zzgDy-_gh?BkaGl?)t_Z?GgTTlQ1xIiCTwI#&TvedBLt!dYPmy4b3K6vS=^(CbF)S> z$|nr~eXhuM&U-S{1S}+iyGPfeo-O1>$)Uba|Mq(q*Gew$Vr-)#(OdOVe4S&*J>`p{ zIvO843^Qsu!rJ#M$&cg|hwowqa;083(z_+Ai5id+w?J+{f6bVqu}c^C0qbmc>$W~* zF$4<3jTr9gD@EwrVGZ{kxNR+BXkTr9n0mi6=Mwhj(T6^+uB$JwCEfD0Y&845WoKe( zRl54kMgZ^0$mq@CB6qeS&>x>(@42Y-Qq-hK+Rt|&D0BYiizjK4IzoQc@fr~=18t3b zDke5aY;^IHABuJC?@i$@=5jEU#{t(d_fmL$V{cY|%j@rDHXUyaBb^UTk441E(<M ziB)MXVD(}9HSk65>KhCrj5m3uc@oX=S{9Ml7!&`wh9Mz1qEyti(yw^#lKO2KCH2eE zuC%JLamp(}Rw&5(+INYzSWcd%Y2z;17^w&(B!!#1=Z4DI8B;Ps<0mROiThkanKBzk znQzPDBW-mOGk^ z7x!1i%eqZgS8cjVt)_%CmZrTDx^;Uo*h59wEqd;fZ`*~Mw_U&<33cwxniDoe8jCO= z!EzYp95fO0^>Zb_THqSty$R(j8#`uv_d}P}K>Eg|2N5*GD+pjIUP;;~>%()}fO8EV zAJ*?*gi6GFU)XPr;wNr!g|b2n`%3^w@w3V_gN zKrTR2v`}=@Es~-{#bSHQd0^Vc1chS>!-xRhN2D!dNvs;xtiXuvh?Ms$s^`9{c7W6b z3)F;b)u217LJ*d#&1&NNYS;cSi%t&EM}S~L>QYMT(gy0+?bJ_Xywznx)#Z}ahO_SJ7p4x-rx5dwoZL^ae;>4brXrk#eCw}!UM5Qa?yEHI>9tD)bm zVKAv-xT;~~Kd6&AbVSyW&IBBcre0W7KYtiuWT$EAt!Wjii4z?(h79vrtDCoL+Rer= z5Y^9ZgU{)x!xy6s$?DQvu{b3y7XvNV)}Af$?lw z3U*PRIITN;+IK~@)xEXcHAvT2W8i+Ez^`y`>A`aph|yxS3ZBT?9&JF2HfV<^Y z9gVT`h`gmVh+l;$P@@be+WN>*eGiBN9-vQygniYLqQD$RBa>VJS1GX~0KK9~q9_;4 zYZN4g2BvxIRfLXPYG{)t8TCYC?Aym{LO}?j$P4krOlfsiq!xw@grn7c-fF?%T1G-Z z-op{6hFD1@us11^%s1XCs_qx9*R!hM>#tE&Fg}6ONL$paHz(TTK(!iB1ZGefhcF^X zKXW0<(;)IfgINapZKAP~v!J5xi7x3;zkU6ee1=;v)fmZSlCp1n(hOI7oBRThBFh)SBLtL<25=Jq($SH>l?H|4K`c`y{98J#VkU`X zjeVhE`bCoqVx|{ejn2;vT(md6Vn1`va3-EOa;4Bz*nV0tW+sj_BfMrRzGW<0h7^LE zN${IVikV3%n@Jm*om{s!lkqW=4KtHVF_SMeQ>Zgj>@icCGE;7OC30+f(!ax$THWTGB;c^*Bvr9IyT2LS!8}PHxaWi zQ=S70SeV;eSo&CuV=b&wEUdFEaD^7OJr*W)7IteE4rS){2NrlHOZ8(5CoxNBL(`ke zmag`e?go}_VU`~JvmS+(UNPqGb(Y>!^Bf(PJ_nY!#gM+omUs9UCgE0hm96|+;P(uz z0(`6hIIF;vg*!1;L3LI>WmX|m3!cMPVFwGYTUHO4a86KMgxI3}Wn7dY&c*^4>$4b( z!NsL4Vq zI=9eTHPiZ0&k|#^b-~(F$BgykuoyfB%Rh)V zRdqJoWSg2Pn+b|d-GNOq&E_f7iVnN&vl!C`v6W}aw$1FeE%vrgeQew2Y}!+7YYJ^U zvuwJ0Y%8X0d+cp`4{S@1Z7G*+`uXk1Vs?XD)~d4=#$2t(>sB*+ z>?W^UPp#QKJg|H54M%0NPvN(pX~Dfxwofp$pSzEn_py%+vtKmCEfuas*4eKx;Z~>C z!kOUzF>&WkL6K+x00RI4SOLUS5qApTKy=CAs)++m`u|jj{f~-=z;r+i8ynkc(Z6a= zKtSNM`V`1XN=hmyDE!y91%pqenSp_Ut*!0Nn>W3^z5V?BLPA1LDOXBLN@iweK|w)T zSy}zlx@XUxb#-+O3=B+8PQH5e>cfW*pFe*-IXU^?N1Xl_SAv~TBK>qO-9!(U-W~H+ zctWl8*Q>L6x>y@9aS+@$c#&Wrp8sOIIe01n_WF?UN9gIw$D{7>7axD05F;X^qGMv? z;u8|1kcNTA2AXNV>4(-Fsm>;k?@K9hig^7EV5aB=ESA{%e9{32NU`ATWkNrwd^Na>sH$QHvi>XU4$>YYZGlx-}Di|4Cf5~ z;ac%$MI0vE8#kYmF6uuv=yfQTCpoWK2*hvA9IOgiM7uygUaNP3R) zbMQ~s30zUE%vw${5%%%xjy%4Lw-&;WgWz1CZ)<|Zj=PQT&xH!MZf_)^M}#($rRP01 zPq|j*W~$Qn?aed{?CM*R28ZX{hdNiP-liMK?7YpuYF*vRG`IBJ%EJA_wd?|RwsP>X zSKsBjWP85L^C+)+_sF|-=Uu+v$W>$H|22Q`r!%YqxC!{LIz4|)i65;ZA;9_X6uK-f zd-0l_m>Bw$nVuR`1!2@FGnEpPmy(c@x&Dtal|!p2$zNAcP&zfHbTT+PIUGV7dumJ> z6l~Zfw2%_IJZRNZY$|_BKxK4QR4`{T4*#bp70`40myil#y+lpD|7SU>EqLw}kLuiz z4&z6t%Ig`c*#3)0Z4G2j@u-)j+`oQQUHu%B1J7Z(x6BGYW+*xpnJ2Ns)acA!T z8}2+con_^fMU|(bv$pO(rn9-Z`P6i_wRfDd&VMQAX|#R(`0>k^FaKXh+y5f%{{Po? zs!o~UeE+J`GXcAq|EN>sMZJRmhdPxKXZ*jbQ{sQrsczGisTi66p-wST|BW%7Q*~P1 ztn)C}B=pbFSabDU4eq}&R%j+YHw&S6i!ik)5BN3y-x&M$D1LSl1Q;C=RZ~4!{cntU zWSW*6sDiN3Y&T6y9|OpMaq}t@SD;R$(w6H((?_foJsqtL|B0~?o9b62!32O3p}1-` zL-5S!Wd|2wDUzUvqsopw#QbWvR8_shKQT7vt_W29d-vg5jyoq%2qXOEI}H$fF9FIx0&nl;uq<}jUHc59-I#mQPYl;8ahfComrK9_4xc6Jt1*Lsq7{6jeaJ-@7XJxU2pB6rMXn4KTioEiT(d@mH$1i<4#aSjZ9d z&00mNmR>t$xo*`v>b_&!I~C+u;oZv8Y_Hv_%JS;n>e|-b-I|7x6XCtu=6SE0ib6~B zUVZoX-Myz2n8<#^(5X6Y9KBMr|7=obZ@-DEC34Wr{#NgxWzntXpmjB1@1Tu#?v~h7 zej%c2`*wNFhtB=hJ@MAf-Q|Af2m?RgRvwq4k6nMh?|tlJ?Lrg(hVo&7 zFn)Ye%*f>*`(IvA>S>bH-p90fL{D(T=lc0^rF+Atga>d2BwYg%EJ@xNtyjEl7Xiz1 zIUZy0tS0Hs=WXxyU$hR1lz!>={Gb-$Cbyx((M50gtlqlxWL<|xcUvKnDARXIw(Iqrxgu%5WLYgD-+CdG>{U`;-BO)C>!VTT?@&ScUD&0ec51oTw z@G-9wMHIPQIJ{{0<>F4R?k}U04ubQ7SA9k+TRWf_{ikV;ZaGBWbce^426ERB1c}-l~V;o-S7QY zhrca?1O2FtiJ)sXLduf*Q7%*kjU!dy#K3@1@j^}g!8q7zG?H6u9keNM?LIq|#`;#f zhojTaYS)?X>DN{frgl7juZF@pLj|!_e}oGCS!O+<3f77is6vI<9wVeF@XO{H58YGz z?IAY^Z5^iT@}lwXXAxDUiDx*Z7oIf(=%0QXk75@(oj)cB0}}PYlhH>P>9r!8QXKqwjjobNDcf$OvL3`C!SGq4^KUcX>HPq;~YZIK0?x=TMr{Z zphU@VU7+K`Wh1mC5Ud3lMl_!$mmTT^#MDWIQA{%mD}ybD)qg=Va`!WJoG} z5MJLQ67SFtIfvvywvYxnQJ)^P}*;}USpC?F&pwsb#br+e3 zT4X+f>5zNRqL~Z3^Z>kzhjDo<8^B3ZkPvmGM%ra6497cs>#h<({&9=6 z7Rv3^qpf;2IED#X|4{yI!P+Rc!Hq*aL-w-U(`go3v44~bw|Bt$8wEV7p8N4vG6dfO;*^<8RY zOVz156(L1Saow}+J@x_dP1G!Q&bM?OixX-R#1<2CAXg4Q1O_RteJ>Ay>W+$b*Kfc6 zwfv*^<+ynGkBK*bciZ{^%nkl0A~X;$Aq}F^5Xs5d2B8xHL%(=KwJ@(ayfF2{r`9E+ zEMoS4E{^pBXY_F!n#G)e_YQKqv7a?SbF@0w!Tg^ z*~Tnr*BGabH5t+{`e@2wovVHz((y_&XRLux5Kc*jC`}DYSW*1f%76` zM$MieIm?|rUUZ7W3a>RcC(acRD;8XPgIk4FE;XAe__bvj?=?st2iV7 zuj93%`VUC>5&ExWL%i$dOY1C=-{;xI8#UPQMlVKK``PRLV)aEspq;(hDIxcv1_o*& zI0|3M{gy!~msc}-I5n;rKnL18Cn2N?#qz5gC`uwr2Im!DzRy&M%|a!XoddJbx$^1Jc6uLZh9P#_7>WXL8n zc+&uTw=4&LE@oD* z2WqqMr8RxmOOe6gp&?mv9||7$qudu zdF!k=iWKX5GE@)8&A_#=o_Xz@Trk}&L|(i{>I4R+XhmbmHCAsBG`b-|m%Nc07*uu7 zE`%f6CWj)T$}QO#6XHI=s8d;Tv4KQ*X{NT*43m+SQf*C&b2{?;Z8O0x{;b`xn6*!0IOlJ44}@HRh$DCwQB9Z(%hd*X#Clh9!b$~2@3x6V#3EYSBvS$RQi%xB z(tu}i2;3n&7hqEr2aSC$qVSwxiS#lci=;Gr$jb%UzEZX=0X=qc?+XkW{u0iPMXZ^_ zx}Agdvk_2d`%Y7YB@L7Z@XW-*y36%b$u6m6yFd33oo#-dB_bJkx%wZ$N3XmzK@hKa=#mf&gSV~`p}7G0-)_cY3vsywg2H?_sVOFZF`+ZcS*Hnz{kB+>6e7?QvEuF84S+cCrzA_!uF8b49yI8dm-sE%=!n$i>f9sxo=aCF*{r zv;4esj-RPfyqh>JNL~xwKks#y(`zvok%bQWHX?FfE-2(X+_E9TK^^8n1+|UJ>RGzK zmy4B^iTfj^?Fmn7)0Wg+41P~gxyKonQtsZ}DqZQG_@LcgXH6$jZagl za(@?}vO@^&U%Z>#n(&_M9;GBK;;hF7tks;U$3$^_k{fiY9nxh1$}>kOFQyy?hCbGe z-js_wFBECrfi^l4IoJ+3JaXy0>mhm-rq`P6K9<%CO6uH@)69*&B^Rfe3(X>BT_yt$ zj)J$^NFEJ22XqfZo7^LG{4XH$M8V$DIq`Gt@m6_R?Unc3?%h@&i|ULGj?BAel?~Jx zO7Gf$_jxFFJ9`$%Xyl|1`d8Fa+pt@F(?A9ce^4sfM5t<#+$+6CA?Y63yNSfQ3 zzOpGiO9d_gh!U~kSl&gqRshlmYivxpp6cQ2R446tDtkhV{b=C?#g}t z_#0zY&XpAqfoNXzxiv&|Io7;MR zsR(VvFM?@{UT9lR#^bX(@>fFIbxJ?TIeB@x`qRhsMpm&?NoGQZH?t9pS&uBM-I{eJ zIdc$`)}rZGt_Fx+0Jug4YvdDd@?8OymIK+crLnMF6D#eVHj%C6IO+16mjF*G zkx(OZ;7wAh6Z+2gd$3HZvn4Wdb>`{!U6CtpMvXg9Rh!MYlj^@msU4qf=q_#?oA(@e zRzGv$+1OpD&1z9ya@^7eNL>R|@I~xB*u(Nfs9_xxoJk9sfq>O7ffm@5{xrGqMLFNl zaXB~UD6%4P4)g42z~O^wleU&L5B~8&di~$wGRD>xJAG;Wl@>g2>)Om!1h&;Jq}3z8 z)vK%3d!^O)cdH+7+g-&rf7`ZzkTyboTX0uf=t^67KEUO7Tcl!pv~7EANPB#Kdtz7n zUEcQO-|Zycj&#M2Oxupcy>^ckfP6zoz6dzvH;*?1)C>(3z;~2~bXMkfR{w6x4Qai7 z*xA4UXCb#)P!Znw@O1PkU29cCA=vy{&!7;R4V^=_-6J90kt>~UitsaNb8kOzIISb_ zHvoa{@?n5HBWAoDUYzN8UXqP(siJBFRM~NTXOq$K0po+ z@J1>sAbSFSQ;bp25`332nmz#yApz*uCi>jE;3jB@1)vv!g-HB?XagXKL!K+45DjeW z3In|f66%cY*RUJX3T;bWfkib8>92yBP+-Xhz&X3NLIA>5 zf`+On(U;w7MWP1rwIkZABfft|Jb2sLz7Ao%0Z~M-!5T{%{N7Jc; z2+DwK4Wi_PjOfrGK{WKZ+qHV~_1@YC`-P6>+6~>^r{m{SWI@A2R}kUJlvc%2ucV&A zkkJx92#AqB)ecgEAM;S6H}PvF6^ykPOl)?INm6yl|c-mPN6b}jbM;t zuKGYV)P(o%%b_(?!$vm^Vje3KA0zn&H458 z?!WB~;O+Zj+b5wkAXflDHo*6jUk2IF0!j3hWCW6ms3g&Ag!OZG_ZKJ)`!ft&Fc`RE z2RSf!(QE)oqV^@(&%$WnQa}1q^5TucA%oQ+f6-xo{x*xyVQWTuR|aSa0OA=+sSulE zBhl9%FS{u}$BKdjlAr6>J`YtICmOs+$Bw8YLEe0;hHHzuJ!6IYbWcwB#!HfizuNU( z-d~wdUNfp&)0vv+WtK)qCP4;| zptn`mch&phhM~%q@9(#=J#Wp8wk*%hsy^Owm~I{9pTYiRH~qWi@OZg~e*$xE%kFri z#lGLE5MYd7cKh3&a=iFZdFkx*JNK0N+o-PiE_iAIwU?oLfT1n$qz-X?y4B3|y*2Z~ zl%n~)l=j5Gtt+?QzR@4^{S7|0-I17X{jtAo*1NF3w{V{U_>Gai+`I3ntILdr$ZbUS z{qDGO0e5bCaq)j@I6L)2Gt&Q>VA~?Zj#Ru z&t(52<+d|?LnC$rf&~L?G%%S7q3H*i-5WrQ4oWlj$`%a1o*r~%98xO)upL5P7LGdG z4J2ZFB7M3revq(G$lxCMxe??{!T9Xsg$Di=BgWxopSCu`@vn^ZwyVQK4x3I&(DzK! z>7i>YH9Kzk+ugnJ)`|H*{@v$xP}_Y9!tvnw0iA#CYT!x1^ANi>(HpOa>UX2PN3(oe z6DLP`KfY*U{JdhjnxHa%@*8l)v2R6b+u3hF+HOKDZDEyP@wGCI!24;VXV>F2LTblr z{{V`ZClU)sOdUsVKHkozO}B>hdEag&W1zp3=mk{1(Vu+onKbH~Y(v=%_@qsaPrf4l zp;jwR&FzmaCQU6*PQ6b4?ye8KL4p^eE)J>CYXTr)1%NO15H;Gq%2Nd95M132CmBQi zeSh3O{`^kKe7n1ijnp+gz4uXRU`-LCKipHSJRp>|_@#DV-=dGt@uxME{tTus!SLgr z(tyF4!(7!K6TjbN;$h{rdGG-pNBBCzXXDJ;I_TsNVE8=3?bb_IhgP1jb~en$RKe8k z-+-dNzU7mbDL0NojNZA0%m^Ltc<{cGI(H$gpljv~5&>bpgrm|_qY>=l25_g@Q+0Y# z@8-Yi^t$ic#h07fBm^+|lJ(46-OQ^dzi8WoTl%?Z0SrmfZIVQizt5b!^yP9)p=u2C zWt&+KqpVYP3Z;DB{;xWnt2QdPKK%n*p4+o(a2ifrvyrKK)#y1_@4C`jXWcINva`%~ z;e&lQ@8$=7dD)MSln7|X7VpAG3QV3&B)i`P&X#IIWGuH^x;yuOkayotP4?@f@6#JC z6p!Gxr$#b&Q}ms#@4wT$a&kf~0cvI{>;V}V zC4LY&sU2wK6iNZS?T3>9Adqq2Jlmk+G*`G??X1)0 z=n=o~`8Pmyz1*uRT0*nyh6su*$0!cD5I&d1tm8z0{|-GrZ~x2A41sa5c1{y^ay|t~ z5(I#x5@HKZl?u6g9CP;2_?~BHJIyDRFvul3gTaV7aEp8jU-o@|;r3y~^07qcQSFr2 z9c01-DVnN;OUw2{n~DLX9F-nUMOf7f?fVteL21yF}u@iSgD~mpar)KTVHm&Z1F(q$H9&~ zCngrtuXFuGQwenQ>7<%rH0GIo<$k=x{PnBm9G0;NwG8`=rQL}23ef6pqYLL%%0O7^l$wLI2pdWH8*}OJ2vWde7YMi39h{gAE%CIQZH&W6PF+NuUYXed zds+@aD9eDu$js;~;9i=fl!%{qEdBT9J4~nbNIH+A2MDE+Z11Fx$`4wM-B0U%J2(=i z(#U>G-C@Mwmj10=x-VDD`Epaw&?w?vhcaBksD0!W%QCcY?E>$*V}AveCeSplHAJx3S(CI4i;mwHh+g-;I^W{x$N)o;YXQaB%h z=icL3#_l8tI+Y$b-!M3_+@H{}UCL?gVWdCeW9em2Kf{~a(sy5gLqgyqq)bdzX`;W`%vlcb2l zoGl_y@kxs=!yH_c3CHLDn*BOl>9n+f29Q~PguT-4Z2Y!VTypG{ByupObu2CSPLr>RAUgenRb~CP z2&F=}$b+W0@{?sQP3%!(Gip_S_Y(3xuGbqj_VXEW)>|*KU*f6Wm>d))34}*-e&QdQ zZJgobHQ+MXPP9=mFnih&><0y<+ccvz)7S43{OhU;KFvx8{t3^xb#~d_KPiaqt5Jl* zim0pcn61~QeWl7okN>;WXI&{xZ2eW%J2f(`^$B^kX~lq-po!DMPd~MsGY;t$cyK?j*Gyw62S=X)Jy-c-qBv2f=dsbm8DVA-x9QZu!9jg+YI*KP3Q@K97#Ii;-0&>b2Y+9+jPhVFo=y1>+3{!tJ+%cOah zOVNZEtB+=M#B|Tgs^R3+4Pew7O*`!LJ^!sc9Q3{2%!2;~ zJfi+t2Mf9BZ5jTz@d$Fb>ErX?Fb}wEHsahpgjb%BcbedZoD)HXs7p0`QO&$@?HI2V zVefS2IO^XN#5pvnZ=KK6-n5 z8K7-`e*XV(^}&!HNQU&lI7ub^yD#>Ckse7fz5nQoJw@Zk?*o|oO3a%o|D!MVAJSv? zUd=!HVt<1*=Z990|L%)D_Nwt?`6pOIiC_3|kK}ZI;U8elqw3O0jZ&^3^?!l2XFAD& z`0?(9zrY&LrnIF3yV_r1?LtwNlrd|>Utldm`7-P;u+~ImyQ=#aSR?12V}P|4|BuUU zSKoKnF~Hgs%CJ%3pJ0v5RsT=0)~e2#`d`7?(cfb2AJU_{D`sy&bmWn3Pxs-k{oSos z(>*;5>G+rQfN%%U;}H_o^!TqQH|UJMnAGbeuG0aplcB0Eub{|CJTL{5BDIz#mLK4g z#5Xo9%$b78H31*D8cE=h{0pox<>L%lM9m5knAP`8K`biwutG?_`VAr&CKo@#iyT0_ z=BcnkuQR~f*>lKTz$_evXjDv$Gy7foHjW#xCeE}wO2a@^#W>QykdvV%BC2+D0)*Y} z;@d(z%wml>*M)$=m@J(!KqXAwPZ0B(z294`&2?pj7sd<$31@5*B;%Z^KofyzDtj*? zx8w>+LT46}L3&_xgc^~q40pIt*7gqNjl2mE85O#Te-3BaVc`ez2mcmE3h|Dl8VKc@ z8JIj81MQ>=?KFgj@SC=qUq!V(ne`s!HphVU?dlo=i=ZN{UYA;ymBg|nDs<(fl$ zOMFt;t6q?{#^g8yfJ{I70Ewk(V`r3`jcFKjA}?+h&V;3~$0M--B^dL89~R8JG&T&w zV0jvpM{_a2L@||z{2{l0-npZ|Fo6z9dn#FEW#P7m0 z&Cpx{;dA`4Il=E53?5}dI8v^Cf-^Ok;-paAIG=+BlUnkt1@~z{MC@#U8{UpqL8?ZUV>K0# zKlk;+3TY4Dwf*SgXpxH*G%|q5gf`WN$b&Ss2(fG$ejRBG0&FPlhJV5mmeegj}Gcc+F+&x;A@a;pAlvfT=^qw&2 z(Z)cIO{uzSNdim;14UY!nYx!^K`|Tsh~@n1=~E^CPnWa z03RDF#zZ--*LX54=s*$lDZEla{;9RDG@)1I5PP!D+#m#@LXVXrh_ZO&APEJWz%0om zL*`PzUPHpp#@z&)>P;>`gF+H6tcy9=z_|&n4 z2sJgpST;^#mkwnqzMX(Giy9?ZOY8_FS#K^9<$@PrNEFH<2VcNIfa^E8x?0y9y0 z4M2xhTbvo2{mIkImK!RP;GiOeLJ)vLfi*VQErzR&1NBwj*4U+5%pXCXRGV4LINT=9 zS87I7SjCZ?st&rU9TZg# z52RC!35fGSE0SAx<83gCdgWUV!yBeV-CB7)i$pZjlB*D3I1vU^lDlcQJ%<>@)FU@5 zx@DSOeyMXeLe~;e=J<4*04zwVASg+dy`@_sgZVBNbUqVre|W?d&yp>wFZnLn1!;a- z@0RiVc!{rPe%<0AE8*?9LOvuB70X8Pz~gymm3c$Nzyr`Zny zJsjF~EPezO*Sto(vZ3zIHE#r7)V>%XMp&y*^J$F?5aN zrbmMi$EgHWxxk*_g40mU@1}$K<7m|u0RJ~*uo90jXQ5YO=@641XEP8TtiH`YK!Yil z;@Rw`@X%#ix*n!<=pA2U&S7Q}7yg-LV8@mGw~mQ=-+)KR2TLEHMrtb@@J*5x4*M^@ z6@A0q;}URwyFf7Hx5v@J>;6D)Fh``D(3(vnXUNjWI~_rfJg@kSw22!EX)1z|z93GY z0wW2R(OyNYd~i=5L-%1}Jtkh9=LGwC2586+y@f39Fb}*aesxo~p_#X3T0%1zGQ1-^ zSF|#~qdHk>DdooDQ8~@5*#KACUx37JB=N3m2P@&UIDPh2n6>oB0{Wv;J9L!9-(S7- zViwmVk@MuqnK;h@CS8ew5%%(ZP5~})}8CPpz>qn}I!*5@}FDS<>)R~A}yR(pPFjlqt z!B0I~LjRItK+FB<)8}EjC$F4&mD(n~Z74ak?U>-$uG=MW7pi#&^3%*GSb2k;X zqrwDzfG7@khU?mxVxU<*pJH8ED#iGBUUyszc6oaq)ExAz!p!d**-|>a@{WFtoL7Kk z7WUK4lO<2Z(&FbPxLzDc6?^&(UxGklp1Ir+=JYCxzcZx!Xx#sXeb_@=ekFYn=f~5! zg;Ez9Ojx4$s8PfR`}cjTJim|r@ZPkL2mbyDKKU~%e!XS<^E~I1uh!u&!r#C+nSH*; z7+U|b2Y+_iD3sjyDL(P(n{<5lAH31@%B9`9V#pEo=B2&#X+VbwU;NA`Q4jUqKOZ_j z8r_!o9Co{SbpE?guOKUV&-|W4H!mQB#}pU%!>CFv;`=kCsPd)fA~(Nie-zn5ZN zI%5`UFM$JTj)eC*tAFOac6ZotA{q2?P%-f64Cub9&>k%99mjRnHVe_5^xYZx6B3R? zl0tVW@O$bJddgvo{_=|kLS<@TDZ2~e8<7L|6S9@Bxm77(o5F)#+`r8Ro(FhzeM`9w zO+ziju+!adP~d+glLlR`;(1Q<+CldBPNPgz3jt{oUcmlT*HX1uCzosPBcS{K+1%J` z}Q+g$9@T(ixDat z#f$xKhpFbgSBm76R4A5E@dbqL#;5Kzz+*;|y)S_Hc^tW^-VgAX0pUrxc%+OIRs}{SJ~Ffo&a?STqTH;1w@bh5yiJnPnK}=L1AX zx(@LsGY0^REAg_S*XE>=fFp>16yl+v;sNf{Lu#$M94=zP5-c=`$V+tvm>a1 z^AZQN^28}2TNI|2%Sbmv$V^6BdsEkH)5GCF=oM5#jFJonl`$!S4f<6t_+hxWHPaoy zZ|^#z5B?08tL|ACGngD1WA4H#C_i?%Y z^FjS~MlD^Y-f~vVwhu7Q2Q9}xCR-r$abz7YBpdoM#Ek-rp-gMmg^5^#y(J@wwFhI5 zVKlHNj%*Z)0%ubAIvNC48k#ig@~%i1ilB>Ur5`VYu2Z4c3Gi?)02>ZTGC+cvAf*JE zhevoY`2eBX@fb#jz`i1C50Lk8sN1~&W;Dvk5><+Wk}aSl4%D%&1_!MtPUJd_B^H*5 zMfGE~w@C_U#Yj7Nlo!Bo3u1#q;kF>zg!#Z!{jM6znZ)hzh>U5_%jtOetE=UxqXWdQAN{7I4%J!9 z2dcu?*KHz4f&jPB?fHN%7!5JI^|;oxi`+rd4@If3JT6^nYG&$&xKjnmlrsYzZq48v z{?6J>Wa&1TjSgYh^oQGkL;iLfeuyRx6`l#+%>+Lt_dFYaT7`pZVkvf%ZZLMM7e-r#8(6kL$Q$D%4LY(1(tP|^bLk2oq@h#Wvbl$=UCgQvMrf*{Az)MhR;zVO zrvG&8;0shedCc|?#BQ;OtVsZK`~paSBx!E<^kslG?dn|^(xZfef{?{7I9zrgz7{(S zBMjD!4Mn~fz7b4~{ym(aJwoRnNs1jw3vNp}DjCUoF@oqAxg{`~J5itFUU!!vJ(%mF z6J}?e;nn*fwXh+I@I;4Dx+b%pcP*!q@P9g?n{{beUU=UmQnwpyFPXp#43qg9qYN8Me7b8h8fC^C<+TQtf&eN(O-EY;@)M5- zCi-Fe?c_~FkzG^ic8^0&^I+{nD?gx)ih4)`lu}W3n2|GXj36hLX}7J1sl~^#rQEB9 zL~aS*Y6+EX?TcXjQVbg7H@VPhD&@6oZCL1Or$h`op4= zp*o9@lClyq-xkv_Xk z?O68g10R{d&Ow{mxE9_W?86hReSO zU}$7dxeR0Wd@Z{*J7<9J@Odi#^1l0g?bzTEmt8yG(0RsDRPFhm1Aq?w1=Zt8-{Ek) z_OLZ}b@?QD`vvO9k=*jYC(^^N)%8izg7v(k)62~e^83}{oX(e9t1lyezufkCxf3`1 z&EwU|iTQHv7av&2`L(a+R%e7h_0SJr)s2m=AB;B2jvY=ut&*dE5t!a}pMI77QeJrW zTM^7^ZLH0zw($j`Icu(J`!&anwTZEDW?3{V|HNp~-0K&l;jA?k)?viw2~kUcIC&n1 zo0MH?RN!w?c550~nbe9|SQ9|4Gxxmj>}0?aa{JU(e&{LBw~a;9XUC`AnVv?YTh6<+ z_!qYX@k2t27mzxwX5A!KkGaF>KCX}%+pL-LZ9w)RLT?-LG3agd6iIBgO>*+hIZJr1 z<dJqG(gohLWAO%0>dGAlnSNUHTUwZ3j-7Pgqva0Kj>L!J-^jz*Dg@yE8eXvm5 zJr{XMV%`Q9ZO=aOd>dCsjX#`b{kWB6-RlvzG+w+^MeP-wc>K3Ssj_?SKDkiX_58sJ zkYf&5Ve8|x&6~25mg=#~^DjxHIvHHaz~jT_S*;bj;FZ<~D|Mbd-4DQKR;Vt)FOv1c zL!SmmPY%^u4E3AUBfZ_{GP^1_cU2$0Zs4PHw0*2D_HlzI)Gn(I==Rm<@hh3n z<8rJMl=g*Z(G507-?mvA^LHjR1t;qdAZ7F~I$nSiq3{ShxW`MN18yqhRZ}UTshm-* zq7Qsu}Xub?KgVE8c>kLHb_3`Z&njWngp;JPOkyiGu>Ie)`!U zeFdplCMeG9y)`pbk3M(P@Oym-lYJ0>W|t2(O>%C)zJ( zHf>D+@~4{XEg(eZ*18zfVFocjIf)9)^~?=xTa=Y-xWtRmW{o7jUsEC%%%p$ElY^aKc?aF%~oPJFt_ zf`;&MEqhbx`d}wB;7l(S2iFNl8)zIWhu7G_h&flYK@}+!VrO4#{)z_2COX43q|K^9Q6cE zjP~hUHFmtEp(>O`VOCo&+YeYAGFZw%mPHp7b2r|D@~D7S!hLDmdm#Oog6ck3;FNIc zJuwI6jYJ2SLj1dcNHl!)k#KmDm;3TJhV*cjyvB?PoPq`MoH~2tv9cHP;%UUzr9)T$ z#MRzpHc8JHk(b|$<|+8Ue1X04ex|~q@r4p9Uk5(azbVZzoWkM^(Fpsb)JB7N8m1|2gMLeMlLo%c%1jZf z0|DbhiALZX zjJcx-9t%iylmi-6@|VtEogOTo*iJmf9d-wQGAw$4<4E&SPQty09fT62Z61iX21`V& zVWh1xe9DUVzkQqQ{XLH+Gc!F%l>X-^g1}3r{Y4|U* zQlr#ri|F-ufl4&lHTuJ;%QDOjvl--)6csvq%Lvp_p7PC=>ty00DD$57R)qSqAIxdN zjbpR2Cz}KW7hRsE$>wFZWE*m8IDLuCz2#&+QtoRQ|dAsCShXl|TJTSkg57 z9~%1cc0Ek2S6kbEN4_on``fP%aOv_5U=^HzwhuTWodGjY5>f@NU(V$lIslJL=#%ea zmAUwmG^bnF$5c0)W5}joQZ!(BGw{k;k+#z@mj|7E!)VOsOB#l>ufAv)7D^PDHA&1e zaxj+|SEXM{)HY{Qk=C7AAE{yq1-UzHdUD8}{;B#vQo5#j79jV8c@d)kU-X_(nzp)X zJ@YE->Xhb}+6~MY3qoWrsz&|o9gJB+`J|)B&-lk#I$zh}A}`br4|al8@u{c&Fo)YY zvT3T!81u)e%=&HF2sv77Ks~R3r&LEGQ(ugvot7q!go}T;N#l?C_z4|iQ~1o_8nqZ`Ok1a!+m*3BaWLDx(^5(O}h%KahXVLYcBZav|MKbaXn<@0J3 zuLeb?T)1(p+`xp-zPDrpukhd({X>1;$#Wr@81CI~xsnj41LL#>1wfqq5pn?Q<+H#8~nVsK79XMg!*#}7ft`XhVr+UZum90zMEAwy2}=4GFkvP0!mn2 z<(n_B95?Yi83fft2d=BB<_(}jMj)6K?9sOt*0>QB&Juy&d^u`?d$h|ZqwVRw-!xw< z2HTWUUcQcnlp7M0i_y56v2W< zI?!>PrFi70iSPs~dmtkJJasn#4H-B7%8uJdEhngH$MLa6jh%nEOYq14ab_!(=R8J$ zd>2Vo1t?rq94VN(pKtxuSWX?Ez?C(Kx9VL-9(=4+d4E0QVAWRqAk**YkJ{XwRuNgmQdm^4Ayyk1hhCS_+BgI*?R4!ji?Pa?) z2*4Dq1H<%-k2Mqw2n07|UY;~77;+g>{)5TZuBaV(QSi8Sgk5roGxKbI>OjwkF}4z# zDY+!V*^E7w6DYi774U05S=vE9{!`uMbJB{VMjZD|*;y`{+%vc07|MP1b7H=|qv6(| zpX!&2FZM=f&;91OkpJ`TW!t@#bAUJNJwS{B{GR+$Ct^Uj%l z7qPG37PuJhmO`(b9E>D7@||8$2buzU!Oux|(170V9 zkB=mQILKC|fD?2eY&set6vSVact=X@dQe2)53 zN!3Kzm0_GDOb01>{9h?j4K+D_XW4KzI8dkiS?u*MjlQZDEKpqF8KAG)=B^}9aBeTg}0 z#IjJY_k22WS%;U0el)_hPrZ6JG;xmOH8S-=0H5>FQa3|gsg)_OWb?qaz3zLZ3EwZW|VGPZCv(c?L3Gc-SY@2!NzRwY&Mn&0|R4zaB+)7M}nl`!hD@|H) z{|O)9izh+F)FABIt&w$_oOtK!x08Dq6F%uHYH1|sm}BSp(jDe)$h)2eX}1QWxrb_Z zE*R=<&fG2#akzR^Z|Kl-uy}df?Op)D7^YWanw7HmidBU$y=n7X@y7 z`Mr?%m3}^9`mOE8o!1f9Z2GKoFP>Rh{x#qR!@9 zmKH;qM@alY_3F&1*Ilff3)SF~(_m2nFg=xE8?WT{B^^)dy|D7I=gw0uLzLErhSG<| zMB(J9*WIxkjFe!$xC%lN%(Rs*`CwfCYpCYpMX5G$#-q7J&9+2^$h$&VZY52@+}zTR zi@CWJPDzBEwb&aenR0Z?Rjrb-zDN5S$FXS;Y`(Rkprn}$*hQv6y+6+m@k2?uG}>^R zDyyrE(jG}q!x(rQPM(1tM{qZhaE|FOX?31ACI1kV4fCGvNRM@T{E z-^hef4hwZJ$o6Cs80b) z@EG}xaKzQn4HBZC;?tv|?fvx8nJRrlK*@9hLQEghcAxv&y)ZcDniU=-QP;eN4AUTR zypiJJn?=c%1)DNjBA%57!YN)3X2S1Sat%E#Y|y3x$zCEOu&5_kghWBPzSq4JE(0@9 z#YpK?PwA0(aXv6ncsMUfMGXi`;xZ8Tl5tNr$6V%aT!(lUrNZ))N8Sqx8w;N8FXn>* z;oxBPgaKd(wht^IzB35L;OX|mLR^tV3r@@Ggi(k!BDbHTCRRzGudcSiNLCkiB)wIe z>5cAxbZVYPPmKB+UBRK@1$qt3XXY?u3A3UYu%r;|6AAqEoT2+sgWhH=mWU1+3F~?M z=%vd(<^o<9A$*Cv3#_?kp2niK`ZzfM95duBpxgDgrT2L|AVQ6Hyn*+Ms-IO{3mpcc zlq&C}RC&pKG?(FwRkC>8FdO)FFcI2u{4wW##(PNONAB8Ue#4P7obx_-Bxls9@CfOn zM&ZX|Yn2(y)1-mWT?kVPK3-fdremNaK1%Cz?6C#4-jsuf>m%ksHxz;=dXP3I_0V^9 zlvG!+Ly_hz;IJ4!c0PFTdDO+)n0TGPF^@cmMeR7hI2i0c22^$>sf`<`w9bD`sOJMi70l^SIP5fhMkLfAe`jnja&S|3&Rkd|@H!BsJzC^zz3`~X37GLK~f$aP!o|wvt?-R52`sT^^ znKpv9DgH(k!68bHzl+IEuwdbrD;nG--==rPuv zOKa(dC?{HbC&B=IGIS2+6q;gCjR{K#^mGkLVJbmf>g&9$g8WD?2w7SY z>Mi0KRrqq%pbW@?G0=lXF0=E+L%`oIFgdPdGMTWKou<5ZR#bv69jT%-cq$Bzfk}@z zKB>ucMUIvu0SA+J3bl$O<;oL;m_!EF5Xh`>zmzyd8ZYhObff- z&w*NrP?4aTfM7TS(TCe1z!x0HFE+49IbeCrynLi638tDu zcXE_pcw+6$X|yT@MwwASOgI^0hQCv7RUz}e5n|va5}h5N?J0+2Y;5t%Ynu>1q$CTE zj5yq_65J3ZnwNxT8&meG?wVNuSdKmpKwSz9~r$P8jR#&JpCjtCKHoa+thM zc#t=*Af479ou8y_ux<@q%r)$E$J$B6f;_Cz#)(UL_xUO8EG!v@ER6@{l5Z~{P5V|2 z3Vjj1%syyjgaaq+j+_9Rgy+G5qxSAO8(M8uH=RGvhovVNWEr4SXDtN^uxTZ)pJ+!Z z)}FsS1X0l6U@WA9=vi7K5T!U)4pNXnb2xDDh%Zy&@+nBLA{ws$7QKOnhABhquk4-sMcwP)aMgl3l&Pmv1N`TSfk4KECRmyU+?`zRWjx<7W*MLJ_6%t+6-uxpy=ci;`T2 za&Gnk!+Z$3DrpH8CwZXlMX07`=SYxz0nPmT6`x(^XZZB`uLeDZ_m3rYkZQT=;~m`% ztn6f2&S%Dpm^LIy2$5)}*6}Q)LBWSR$s@4`drp$uw$W=+ERV2ktVR7HT{!nO4%f$? z>)YvEwbaU}pGL^Sf!9gzab0(g1O`h5$AbNpW6={5^{Ac2`?7DLEDzrCIv27CTcq~Q z%56191>!|Z)T&3hH)U&7JfFlJ?XSFknTdipr@i$k@#lJUR^nU9*5w!;xMK(_3cq^4 zl5}5TWbw6B+MCyw=ZbVN*R)U|eOj15F)4TzpDViB7G}w|K5^}rl+(fmY+anfgHWx{ ze^{T}NeQnfJmO(BivA#OwSY5zfJdbr?#Vx!`buBiH&D>FWgDhKIruLn%CPp$bKakI z%$sHr=`l&j5b02bD&Ae1yVly|Us*;m@(a>!!Wnt`|7PtX+?Wb}Wn=Yo=y)u1GqXWu zYW~je#a|V0?@?}-zE9(Zhez~uE#M`8BHqJRV0wm*?ArdR;CJ&zif&E82@cao*467M z2W-sw-Ei;gWg*Nzv`iO3ey3#KRD#fz$3rV`ULsyftvb$w2XR#&kGOJ{^6hHW9b`Nm zKj9}QxEFqDRy?LROq~Xrej5dUc9p26_`)P4;fn0w=^MB~Ny!wL^m+$8>2c-FSIs~RjQ=Mim#rP-K`V%ddX+OLWT*G)0f*j;20%&aExYCB|J2hJmQvvNNPp2#1r_2&9Q?Gry&$IUV|ugVZIEbSce6`rQY5D#e}bqwm`jPKj#<9uySF%=maG*AlF+r1og5_5&w zA2D+^YqS7%JQ?)J4pE2*l?equ0t8_kgJrN6CL8Rors%bfgvRrLV=EK+v5uUPu>AET zj}(|R;DQwT>Tb1{*Wl%|E|FuccH2_71Ky=CzR#fWq~BdKnjXp`wrEdPXT8x6yVB-) zbL6UEr6gCr+(m+aH2cli0+q}L!&l9qdp|6Ayv~+k{L{g)1$1Ox8KjIR5d2-_{!lvm zuE!lUpfu(Bo1^O6Gzp$CN@VO;kq9jH%CWB0#YpE*0%IRb zgop2`89xt>@{avzf3HPV+v?1D%P04zT7Xxson35|@rk;J)rkCf?EYom8}1+S?hl2s zMMZC(PhxQfKg6ICwr>>RBBSGxqkRxBUX8eYo?|X%PZEJ2_aw#;Vb-9e23{ViZR;~N zzMR`2nKQin=wi;1;}i|26{C_g_LA5;ph91piL*S?cJ|kmZ*#k(TyIjYi&B#bRd$1! zuRJx6E-gttn(-dETYOWoBu4n*Kvap#LP^RU=XZBN^Qk-+uk)(s$nEZUWXA(ffrT~c zs?WH19h3bt6&b}h!u9h(XSrSC?H?gztdvvFC$K+YlZn>^$Z#ASXLT(VST23sP$bAl z6dB`n4+BU<6QzoXGVMgUWup865zAMmq*3|GTovw@q;o0&2l5x za+BzCv!Zf~_Hs48a+xuJFqQEvRyes} zl%fGj$BUSUCSQvNI8xDhp~MOTl0-w5&;hKWs2&okDhDc21Xa9($|Rq)abg>^F&(5(q|B%nGpp?B>ns|Z!6X{a+;Xk92-2MaAHR7o6=9SOCL zp#T&7V{<^w=jeK7_BxOj1+r2$*RF85qi~N{S49HAX+U-ws@My9nt~*G5%s*FXQ;@k zP(TR|)f`QZw0I21)qjtMO32iRh7!92iB2@sq$@>9t4W1SgdY{_eOpTFUlWWHlNKBK2z6PMINouS~ zQWI2%t(3Ar8N~qZ(Hcsq&2TKzrnpLy?}=m((S(L-%BVV#Nyd&p!SlD>cddSw*t7zM zFt0R8TA-?M5Oyq7$`VzM21czkj0HmU2&nC4@Z}Y-Y*4FXWN!-xt*)Q&?b?Z4;>G{Ld_WM^4NSg}gr$S<>2=^LT36=Q;_3=u#EUJQ)(Gr;` z|GrYu?9K0;(c%;eJws`fIsiM_^@<7fT;hX-)QF0-NNSQQqDeIeopsRw#@fUfawjRK zNpqBS`n{%r zAr7Bkp|J5caJn@dj{)#@G+bgD%9cAqTw>#TRSW&disqxCc|2Eb4vB3ppEP^1x- z%uWZ7ZGxKuC&Po9&ujw>u<#$2)8L@#Bc_f<*(v33Qis9BryU(|T8HVcj^3DNn~wT% z#w*Ya6*++SkI>WKG?9ZrqkJbR0@lOovBaen)0<9ZtG~Kl^Y``Cma$_X=3R5N<+;Q0 zo-eXc8;^yPV?zzt;S+~*(nT|;4;Lg+3)B)7FONkYu0^la#ob?v zp&<)h%ze6yvy`1(5nXeIouknm3(?s`p5GPx9~%X;p7Ch)#dQsZ{AR2MTsUvd{_uC@ zCCmvKtA4%BzPo__<`<}<)g@wFd2*4ERxn5UX1|f^xJMSzNPC%5S8o2IMtF9BXhEvX zAd$vM^(Zo~c(6rg(lZw2HPLcDw%IRhNFsXZOCYr2@Wn~j;f0Lhr7;SgR`-gp{*7z> z`#{KtBa6x8-}QYV#0-J)NX_;fxzTaUQ4$)6@IV^jpaD#)-{Odb5=xo-1e{VAO{bt` z8@PfRc*qR`TMd-hkvaECvQ=w$(Rdve%Ah%UbnthN*Lx=>tjne~v}X1Ao5zEj&B)E6 z#ZZLJcy{pIQZ0&6ju<J2B;DIVKrB;ivUVB4a9;JS8zUMckU2k6mlko|f4J zFe*J{<~P&X(<$TAF|}kIc?6t7sIbB>Q3I8Toe);&KYt*0SBC3sR@PTm+}I@Ds;KGS zte3BIKiq75SOJvlZMw15cw#HLuD9*wmg~V>e)jV#V?-Bfr{h>v&gZQNkLA>iWt~pq zqFhC8(Z{jw#ip(SD1bC*1+Bq!8iWFbXz&;c{MjM!3}EQ}EykOfL_&A55jrmjv<{AS z_Pf>&7uAmQH7$IepN$)SX7L7&1({%;n&d#d4uJS=_)U79Tn;pDYnxt&e7V|6c7+-P zUX8jzjR@nv4(Nwt6KCxpS^UetZjAmoIp)puNsQ?;@(2j008oIhkfYUxElsljM*#b+ zTInK);6%Oj3Mz6E&E-a(bKmKZd-JB2I5V|V9ZghX`zk+C?N|KxV)2CT%~{;J)(@l! zu1nwevcK`yf0MnvZQb*Ntc_H;NzUSX?I7E3PU|ETx30&aIyS$bo?Pd<(I#uLW=z}g zy-lnNV*JRj)z__(pFooAAZ($~Rjqagd^~g1RKCSne*D_V>*KXolb3Wmpy*k-O>p;v zCpW)rbf2I&hmx!Gs&oh)ilCZl%i55~o!|a+*4d#7ZKu<_O${cWsc!;I4~e?84T->R zMNN<%VX5`;P!Vg-=&RqdsLd&%L+Rzs*+;+U&m9)tJY4$nefg;8Q2g9h=a<9hkGDL> zwzM_@&X^BtLMx2KOMm@*-S!$Q6^ZNqQ+TUib3$mkzRcWflrczkWM%$$OT>5SzizNQ zB?zF+ycxc&gMgi#Pn(PfNgGQgaFu%{Ihr8)taeJLAL`(L$Es65I8DTtI6ZNQ$e728 zRHb=7U;3XL?1ar~1&vvmL8(A~Q#00P?*Z_w@r0U2w94$}FdTRD&&QwrYq&eobr3;J z?sbP;5qNa-nv<`CY~kr+3Vtt^zP=eg+jL2XcIpB`{f-T{dJu)9s@JK$S`+YtZ5oP# z>C!B7zP|*YalO!R z(R~C2DUIOh8YI3kYiFKJ2S^Ec8;)d(1SF#p1n7{lBoYlWnxO7Jb2>maFFe)slGS6N zs^D{AnV8??wr0w^4h5uF*{L7)=H^OB@jMrwFMt9<`KUxm_}Zu>A)1d=UAFIF;hq2x zOuP5!2K_OYU0U>ay!76xth8vU)^#80x$h{sh7qN$Rq(ve_{q6|&*Oc$uiO%E>gYo~FW4zeyOMrd3s-jBeH!z&;3{kTK{dE_^JB{!n=L=L z^r%sAqsx`ET^j6C>7}lvz9Br3~Ksc^mPMi zgd`A(^b&f<(2JB%q=NyGBA}s22ZMls6hjB4L_h%r41$0N8aje#=!k%!Nykv6s32l5 z$cgK}_PT4Gz1Q9Q%$d1!^C~Ygd6Qq}m&y0}JdXqTYW=~k0HK?`2(*`+FdMTn;Py3S z9<&s?*UchRM;P+bdbih`Xe#*uz-8}v4UMxB>%k)zZuUT-R_t-lTBS4T>58TfADD`f z7vp0M;djT)gt8~EnJ34A9ELg!4f5v3PcuEXyhG+Teg-UZyUe=z(a_;Y@^#fl&RsA@ z>$WcOM*F&yt?O|cpNS!0f;ma#7uAiq679_rO@y|??2fGC58o=c-(*W8g^6-|!luoP zxvKWuWgR`?LH)+O1Gv-6CKgpb(Iyrg7{?0v>)zt{RM&>#QaYMKi)qz zU)!T`PUR}v{g~Gg4b}RO1C*s*?#T;2!3|*s|#VY0ol?@LniVX49=yV;s__FCXc=Vciu%NGc za-P+L4Q?)hi~w8(@%EIjAI}@3BM(rb&>>$Z$8QpRCWpLDPH{@X!s3E?V;g-Q1AAd_ zEG;p`Q&-HY9!6Emmaym14Q_*;1wo_z6oAFUPqTLcDU%B;oNeudWkSg{wM~{QJ*tby zb#8!ShV&1OoBqD}p3}b;H9mjWn=B6vx(}~Gcvho_?)Dj>@s&e|EclhA3|>^ZC66!Zr{N^QS7u%SlLl>t?wkWt416 zkz?y~0Ljcc9XW$ZKF=KN2{ko7$?w##lDOg}{Im3Mz`&_-DgRonbgb*LDNoa_QzOuj zAy-;ez&+5M*ga0c(^H|6nbz;7A9A0}jIGkV=hFO=r>UjBmc*>psPvA1=6K2Vx(0F8 z@Y~&0ge&LtHl;EW2?!VB$oeoN&1yFhrooAz<`0=rL;uiHH!(8KkN3*8#D7vwe z2wtD5w-&auc)tBAo%?QSD+gyf(uVYyWPBb_`Ce4=ojq%X`Nh2ZL&nHePj+}-y(w1K z$SQ7ihbKdog;`F={PeY6o5Z{Ai4D$QW3H519cFNIRx&q)X05@(3(>a7vrGei*Y1m0 z-XG@REWDQ2?s`DIY;otIC|T&7uqfyOi)jWbVQ)hVz7kDHX!2mkIv=xMAEgUffEI21 z#D5i!`JK6i*C;} zJxh-_mbV3_{hU76hP|5ub?8o4fUnosbY7EmNpxx4-3nZy+<&>RBkn@d?vJmX&IyvV z8wo5Lz5AtQ6l|Ggd%^q2HdCyv&bVbIFX8YE$y#)umi}?$IM;O-ha<*w7(h>>i6y?Y z>wW2J#X(*_&$yD&sv0U#U<6J?^^EKFS}qk92i!QOHGE2$QP&^xfgnU4So zQJ|4_+!Y1%7*jfjiqcuOaI5EwJ%SH2MsxK@k28c&9(yq)3yx3dbM-RHo2W(-TYc{E z?x2t%CfsNGlvsAj8{o>`bgJ?lC}!|=-91x}ry}*%_B!Ucu8hehp{I#^C204Hv7{e0 zo=HM!m?-G6dU*TY_JI!lh~J4Na_7IMn35(D#mgHjQd`=|Pxj0F^hy!7E-8`%6K{h) zdHrbrA+gi(DY3TM7>f*?uoQ-6s` zc+!Udh)I%r_)`CfNw{-o8Ez8xf)$P%>kK`~e?~?A*0C}C)3J%e{!dgTe?@E<1sg`Y z=Ko$>Qd9pg+LGSh-qF#~{~yL`{_=>((u!36tw+S$JXwT6dHhE)CW3{0_xTOT*?&uU zn0t$R4FAI;^0|7V_V2|Q=UV5de-B?7Ec9!B^|1H zCY|ewE4zMv-CKM9UwcG~L}MY6HS{Ee=D&DE_am2`BPg;s=U%DE#jeZ#J$!}SZO6;nXu_TYE&d+9D$ipbm>|lyvwg54 zIsGks^)lmJQiCj^?Ug8v;uN&g!jU)Y`|t@T z3eM4y)<{h&aG6Le!Qt` z+x_vDGN}CXUGq$i?q=)egP*&PzwZ8gPlX1l`&=`T&gS@i-G`*j~G#~yRsOjgAWfA(TJ6gmk4mg z)B`SOmL*nSbkCSR1y+RxqY)SsM}gN7TN-_HjFO>;S>?Q1M1&o3mfzDW!ZRCaL&zzf zR9Hk3|8vy9@6#6j^1GqnlC3@^?QR$_um@WDa}~sD&tkVI&Ly~2f=~~;>h`HT+4mht zMsr+8aAX`+b}~_HehA98-;D}h>|@nUPqZb7XIHv037${PgyD%?_!6QpawuK%LJy>( zmkNh90I-!wtPqwyxfE=MP?9q8W?+iAqEX^;cX5s@?J45Yq*R-4bk?E0e$WqUmZ5th z|HO&ew za)(Q|JxM((=BnZro#$1!kKnj@hk^S9c=U9dVY||dv8IH6(QzVRT8}zxdm~hd#7jSALUP^>ju~Raujq*!gQz zkBJ8M=*4rmlQKZHKezNnCbg zUiLBZNZ!pM#l4nr*Da7V}59FvgCJ!+&52hT&rT46{N0RFV0T43j8iH;A>$8Kd{>|k_$9;Y8P)pYmd0uSkgf90y z;2JU&T<~}1;p5>7Fx^da9dR4qX*kTDnl_cWV%0OW+tOcFQ3hhgf*pg6jwGXxv+Nb> zauoq8N)-~3m8Z?08Gj#_SRz)~rYAz%a+np1n%_w-`SuUwlZr!M+2o-*5ZXjk{az1~ zBw*XA^T%{qXODDfxyQ8qi*Ozk5m*3yd*x&MQ+-T3g$eo(BK41CQu?unQ@SATb@6`Sy(3Pxys8&&k*PAxuddo8xX)hyBV-rUCFh%8@#tm`;O%^#4mN9kO6vr%zSEYt_u9-kT1LDcqZ7J$PUV?oIYk` zS1DmX7Eh%jw8gS)w&>xh)FkN~tFO!#L-(?d%JXa#_2`3=c>$sa(he@nCUuzI)aW%Z z>bxzjzKiR@AXbdJoov7u=RT25fwe3%KIJ=Hse8wGzTjCP!)UIdR{#h?3}NR}{#kXY zYj?XWmEXOT;h9J{{B-Oq(9T~RE_ArK!u9Y=Xqwy0l5fqMj%R;N`sK5?ASiF^?Y`Q& zCor$JL0t*qWVJ}lfUY1fqEjn8o($`u0lDe$E()}r4(FpVSM@_hubgHBNS7K%3wqsomkWd$40}a zzv}3t5k)lU;Q(_n8gZExp)(6L+k(fU6QioV%rg=O&V@g%_KZ1~thNcX8Dy3oNIU5%q~oPiS^sgwuD{h*{~0VSE|0Qiz*) zu+8C&4iyv8vv=NLkH9qxrxFr-NEr@afISr0WlW}RH4H18BFdLE6$w7n42MHJytYyk zzv;K{WyVq?1f5g%T9`Q7p&Bd^rQXDfFS>$-SUxo3G)_lZw&n^KhVX5`G@cHJOaYS}v&-^H@JGhmZ6}|QnHBNjrE72n z9y1rw+Eu_#%cYs-{ zMu88S!nTqV^R+V(m5F|?%tb`PLIzyn#zjGVN|vlEW7ne(GwYAO(L=V5ayIXw`93Dx zxR_pO{!NF92lGEGL{9@Xv@@N_S44dxxG2oG2seK76#?!Q<$fb@@SWiE2deGacl#N$ z&FNIk75041FujqWM=c6VBXkquHLDXn`>?*5#op?fEqj-h_#KO=MHZ*>>oW7X&bG&)=#4IGV%($^|4g*i;mX3-;TdeF|*+d7KF z(A@SgIxKAenZNS)GP!105umW`d)bHLfb~`;CtBJ*PxP;K`2I6yK1>;)C}GVt>v4LN zO(Dtp3e)s#zHn4I!Z{znLcSdiZzls4h;ijy6-$=azh1n)rB=38XvVR1HNYyee60+e z30K1dql!|T(7-}hX7(AV0;=SDv-z)2C!hKOrSN7Fhc!^`RCuwb#Z5X~6AgSHolWaM zU74KJMvEv@E9as^*=sD?NqGwBT4!8%e0qXKI;;x~)JGu@1u1XRisT~hlm~{Z(qKHY zz6xldfGepK7xaX+E}j}8MTeK5?tO1()}zDgw;Yr@m``Y1uy3Xvey)wWSsi6jA&3b_ zbU<&WRYna$<*6xBq`Yl;!~?DHJng$<0YG-Y2V1&nH-3~bPH;0jY8*CnfX&Qh79RZq zb%*n%LBnCYI%Rw;mTX0~@wjxxjZ3+^jD_Xw>u*KPUo7%x({ePzZ_UD+&w&L4v$=50 z5tjEvrsK18nB=jA^FIn@0(4VxMdUU3mBVd|!nwktzLZ$jGv?rRbgip zi4Do?4SSFB&uhEr1!a|Tl_2_>n%dn5E$?n?wGFm2g}B7Lcx0XLpW=jX%+F{n%TMVc zw9Xf|oH~{Xj-lKMX!y+&rp|{bCYH6)3xA(xiMXW8_C}|olf1rV(S4I)G`FjE)0M)8 z+6AR>VS(bs#{>x-2v%J_Kxjp8=bJ&@Hn^@lE#R%@<9ij%{N@(hKgegSEG$oTYgeDJgG{441G*CB!TUnbs2X`Zujmc zwQio0Zh;cr!U`RcU)?4^ZM0sGWQjy>BR~w-BmcNZJV^>p(4RBWmTLsPxPx{es4AB9 zVw)t63K@PpX&9U=?nOcv1p^*om8_fKITgJ&BeE)-MjDzZo)jZvn?BYabxsHH2&K<< zvEQ3h0wZanE{W1iF+pAchFwt1#REi%EH_o5E?nSaYKX*S`4J4l=@%F>t_CwkJfg~X z(f~*@{|E^&fIbSr4?aCaX`iu?Wk& z(h#&go`U3O;7A@cpCKXoxoj9@_-(C83+~{jdvt2EBuZ z75y3BfL`1f1Pd8K_YUYubD)t~LOS9l=)&u+&aa;#n1@5iXf^t&o6Nx8U_=KVwf74S zbAW6G_qF{}+ZjQ;*F%JJLHOcdoZBBNS{tFaxH5O487Y$(aUk#{kOhNyL_#-V#!w-E z#zV~bn=DoBrRO8mq1F;~??}H$h!omG=fpb?38gbOm{G8YVzDYT2m{RnypWIpr+WdU zB*4}rgwvu(CuPXddmM36{v1xoDMZx@kJuNQ@=~1|U3>vkWmY#c(z@Zzc42~bpLy_( z97Eu9x=t&04RHB_tka16`6exVJ^CWzCc(KalN0;61bX%7dW^{QR%1d3LWCb;47@@z3%-7CP$DZNdwl zj~1w-3zVIOxBQFUOAEP^-2)*b-+ztu={K+^^*rC{AF3NU7C--VR030{uVCB@J7k7j zSy_ZoKrCuYIf!R@HqUxTwe%Lj1~!I7%)FFpU$6xH@~Sd?e|SG+`IoTx2}L7r$$nmL z&?%w5$R@NUvG<^h{(I-8X9>f+n!9mWF5qqj5=TP8YJmM#E4WT>%NyVv0tV!FBzRdd59JxUsr7JQnnXwJ`b@MXx zr_!-!q_HV4louLOGqK_FdsSQsb@MKcs|=_F_WAjbh9z^dAsoo z%b5Dd@B#zPn4H(Kq25gOQ?g1hd0ULq!2|>~8DKD}F}lUNyRj8F`6d_<7q?A0Gxe%} zb4BA!$=H;@?*zjrB>@g%2(Fy>&b1_-rRIR8Qb#_XPq~~k^a5(VoC4)JF zhj%#As;vwiU9TLwG?TtRlUUDx{MT^37oZiT#es)g)G^*+ooI}hVq0@@m}7MO`0mV= zgaFD$(PUw92?}Uc|NXCc>DnDI==R=8ah>M+JvKwh;e$QSqmmqkA9&77KZ^e#aK4BC z=?9S$5;9qHqK5mjt33-#ds3@Q5WsT!+WXhG`>qCa`iF`v`@mPuY~trbUuBoQ8XXgA&AZ4OU@!bVJdPjUfPbg8>k3;BqM7$b$jC-veQKgONh3SqbZm3=ivt zRkahiD{e{r>X$ z36a;fjPQ@ayJi3wkLwM(-FupC)WhI2*?n}TWVC=Xx}>-4XE3&3x9-~Xk#&FTve0%! z=%$&7QZs%#_hE1G@@5$ORv~37DTh{w+d}NnGDXINcem~@?@oCQ6`a{V=P`8j)ere! zKW^o$HD9KcJ((zHn^Y}DSBw0(C$j$Z{EvrE(8xmo_$g|0=xI-5!c^dKrg(})00+&95crH-J>(+e@lUg)eTmFVqT43CHwAvpx5#^*UNgqiO!feP(t~9R$ft(iP0o}li z^*lj4gm+e=z_$;|7y;9Qp`?wV0{(Kgm2H&o0BUXUmujk4&j|);>Ik%#M@^^n;H94@ z(c}8at^ulTY$aK9=cXY-M_8*(xb%l+lZNTf0I^6?Aa6ocdE=G)MaBK6lMZ@Yu^}gp zpRDwGpdQw5J)q?8WF1=MnI@n&bdFCn`G#DPGU)>+qGTYuQ;qL@Z}(XC`< z7RR!oRxH%UQ@lJ9e45KE6Mm<6Kx36$ne3ir$$Z5p=}JXTGr>vDBg-|sX2eLwij;s2%W}2LrWVUz6lu8k*Kgt}LXs`t|9VtzDK}=`#XI&#W zUuNEq-q)0S@Uj2vdS%}Bhv5?cfS(uE0H)STt&8(RKt4T84O1tIxlRGP|Kondh}$Mo zKUw7JNaTFbQ(SoJgQobX<<6w8D0=edo2ZqmS_$H-xy}jSQ}X^jVcVd*NalQB6&jR zbuCgOuMfe{U>qP!6pBuhxn*bM%vE~%g6^LMx2;NHGM@o_R3{I6LR5e4PC1rrG*%N+YP4Ct=S zeav|(%_rgo;21|T-)T)lVPAW3=&{U1;x{Af2r3$_J|i_te{k#FVCHvAeq(``4?Wzi zu7+o^@N#`Qeg)UV87{}d@|Msb5J&gM&F88NVKFVIQpLgM|5Y%Vi)&4O)2<#_3w9c!1I8gU(ylD8+Hu3o`K4Yh8;?X+h^JYd&0|QkISF7cY(s@6l?tv zgnRc~)9;oFceOjVriEplQ$&8C}6Spc1dx#JgIQFc~6`DE_9Q=I-*jsn>0 zb)XI2Gp-)jFebb#N0Kv(`h|VhTt6=wAvwCweA@^BSFsbjE)Eld#b;wIKwxsFg0Xz zF~{Q3uX7pE{3G6HEP@;3eATO6M}vIBZ!P`u)gE*m3$F?<-HG$ld+}X8b|d`u!7o27 z^fWD5I-(pI?{6w|di<(yM1}ByzlHhfiTtXFyGrp4%H#Cpt&NCk{eu8p`st|(>BxJw z@qv!jr>F1xM&9>02y_`d{j#YlvOXj}$bIwlOy@@A!}x7hCG%LxTO>78W)xwsjqZ5YpWi*QBE!jmC#YRJ$#`^^NLWItYy( zbX)#d6~*v~oR8add-Zc8>gmD3c_P%Et_75d?nWjMQe@m$;C|7)!oLX_=I*Op)zSS* z31L}&?rVaZ(S!QG!$|4w>k=|C&ukMe6j~$?VlNgKe>{>7z15h{r~r3$$!Zh=<8z{ zjKNeO^7Tvsg>)*&ND(?PMP^I=?$%MhdK}Jx8 zK_<-2&Cy@cS65fxzJ0sDzyJI9Z^p&_fAsjn5}^D)Y^O3M(y1`_AxinbF-FvFQTwZb z%4Z5}+8HcCA;$Z^W(l@Nd1c(He)Ub%OjiHH7@;8+Iyc<%Z;cVLPC?0?(I5Y&z zs2!iy^0^}fxrcf0G(K$7Dy&6Ae(kElTpO(e%Cx6zjVXBH!+<@gQ{5>O0Rq4CXvrhp z=q??gA6rT4Hls=M-n}dFI=EdjAHlOIwqd2%KyJJup4GR?Dz;HdJ09<&?ajs)mF>-@ z7N(xxo$#kg;&uCV<4C4Vph_aQg9VQ62^9}>2Ho%LvEWGU%Nt4wSI2k9@;j-ml1zEN z7y2yJ53MpkcS&4T=91iCRg|JfqLWyDsFd^ZtLCo=n=x1dk_DSAUX@qz<7@$k3;%O5 z6NG(A%Er(*7Q9BC!IpV{+1`veXLZekhqGpz?^ZPI!Wq%a?LECIOFo2j9Uq^X&D%x3 zfo{d8WYev|X_{$USvuldtfild*AQpo0^hv3UuAjdWTe_Lby`97a^iUZgU%!|$iv4E z=!LLjMTD6f9>FWTywu$vK~3&d`JLvB_=`qCb*JbvDZ7zx>)Xz-wo2ibBM-3iX%d$o4CJ<_Qua}{rb7H zkSr3f@&7QIOD+sWd*K+S6l9TN#&H#wACytO0x?eKNCxzSfx=ohc({XfdcbR31#9k74B8kW^K7fgfv8h zMfOl4oB$GML3^6ECJ`C>ZZB0et5Q zyhv*t8>o%c#~wsIG_*tQLAuxHA$ohMwvSValvI3s6^lkvmGZfhg?ymxV%e$FUe{)8 zq-7r78_gLe-Qw}+g&0tKk6xU(IF9n}4Gz;uFXzfqdTlBo_rdC>DuUI&{q@01@>pv9 z3QuE(%wfSdD-@cuKyYh;JB1_7v$cDWZN3HrSy5S-zGr|NG z&q}TkvAw^C?O<}HF+=o5D=lw9wCtv+5OI%LMPD%xE{6)qqog9g>A<@My07jzdfWGE zH>l67lDW_5+Th|_z5VZ@>wi= z=_4}WFb6BR%Q2|UUHx+TfrbF`t=E2p_SHwqb+DoPBE1EC$P1x(o`nSwo%7feuI?|Y zGNyLfC=)y7`{PvlP-hj{t-@XBEp`n^y<6J-R%46yMH@Mht+ z*#*$AyL>D^I#k#e(Nr{W@8XB=$G;0l2eHld^cv$6ZH0hr>@?zKt&tTrHAQ4g2E;){ zT0JcWz{Eo>PIn$zZ9WqgC7=*?)z4;4;F!&T=2%0HPS%?6&u@eC?^H}M?)5N z`|~*?jRITEUUqaDggNIKv24B4;9fH-vfOIq zupo?U1{^9Adhl(_=w;wMamquzC27>|sANz3nLC31!O~_k+ zy5sipjq~6S@A@+JzCdc`W1aWaEiTo_+F6)3TlrWZb%1|{f*h{@&`vJ}z1D63d0C&h z1h-D!KOK0?{K7sDcLi8UTewSuwwhsA)33D8nq)b&bGh$HDtAc8u{{T7kO>8><=c>w z7G{iWuDRR3*-D9i8+#*=<<)D+24qmX&T31$5JLCbqx0c+Vnr!h9Kttt+z3LTl0$+x zx9l}YFg}^9z~qbWd0M6$A!#X)WGeGXI>mK14uswUX$3c=Whbk?mgW5_kcJC>)ZMUY zc-DnG*yyT;Y=`IPCt9tA-+WLDce)V_AW9*j&oXPTUPz|3J;;6!iS^(Nl5Oct+HuX6 zx+Eyat|8^$jg%n(1ZPMo>J%nsL0kl9ww^@o!_qBRn>(X|G_!FT6__QVS3o?tiRL!H zNeDN233uz!X#em&J;0kDu=P>#)0kz5P11WvbK2Vql}~9piGqz}(_7~;@K6`8nd)lL zPJ!IYqaroNC;10%Jv0#9yuseGxm%IGf@Usu^9+AiQ;&v zl6g@JO+^M%FykaMJG_P&{Zu{$IU@mDB$#y#SS?IN72MUiK7h$J*E(A5ygw83TKXJ3 z92lkwYMZ(+i;lWh=sJ!$UVyVTqn=$PLE4-NyM93$RFGq(R_zAn0TgSNktm4r^Q}5o zKtx8Yfj+3EAi~pQigcU{t!8mREo>k>8Cm>UF9n*8!$$%S2asT1e>Iona0|E^OSmS* zj=e%3t_FifC=I&tk7jz>9|naholk+$UASLgf|a1oVh(Jv~r zru<3cT*Mc&i?_a6HIj2%)vpKyTuEd}?f8=S=FlJ1=XWh}mT;h*w!%kjCgP3v5Yw`b zygJteF)0%y=l-D+YDJKI0upgDfnzNT!IUj1k$s{M8AQNq;ef(AFk^CHrlg^fcDly7 zAY)Vr^?HgXF$$3%kB3>|X44QrW(=hek!%Q@Id?dd)QBrovoK97ytD|gqEBKJc-L@b8-q{j{KIkO8k)ACzcl~S(-a(Vu zpAwJ%5*nC-#K!>9sOzCok@h;t@_wNm7trGI%aX+|!X{jm3XxGd5H4|*LH>yHM3VZeAZnC4!dUx7j3l$DYn z2!qwX#tW;GL_&ECn~6v>G|0mx#o(?zr+3UaB?!S)B#48>ryEWXGBp9^0hqwIzLBlc z@EJ77j)J@t9_!+pTX?dV-73(S08fE>Xre(G+Uac=FU2=^3dlhiBC>Vwwx2)HmWUJ_ zvb+@l?BX?yABYc`E`J?U_FCqq1S;^79E`>H)@x0M6D1Zy$aEe?3h@R4_)7EwK=EdG zodn`R^ZDF?@XTBo(jpdOc4YCS7pgr%@IG^nKaNj7V|mREmTS{xopYEZ$pOQ zM>&wnSlAHbIq|K9Au{|LtVRos%Eg=4R{CR0q0Dh@ImfZC*#*R3K9L)~*SZCe8swnk z0z^l-`>o`Ykvw%uVCH#B6?yBF7QW^~Z_SzFD@(j5YORvtAM-9%)QT0I)Q~H2=6#@{ z&AgyR&@VP-vWWG^-edB=hX{{d#MN8G)b$Dw!(FOTmNmg&{O+_NoAB4isX4*JuvJ%; zxMvuSTZIlohDR@@(>|IWIi`X^pL=W-D~JV=qE#hu4VShtXu1zaMWai#iqu<-1_kfR z)5Locn0_d2=saIIB4^m9-tfyC*yI?;3~5&C#2me)l3IOII2L>VVzcb?Ms|~?7}zEI z=dg&Az+?Qlqb%xn1XDAVbxFSp8f9I`1*TW}NF*n&%&6QKzO%IT;mtwYAuy zh1Zce1@cr=g}t*a=~%lMS9=PhNfN69PR3*{v^T6O=LkN^ixoIfVUoi^FhKLW${Z~-uhmVD%Z{FTIL!ie7f zpjGjjGsRn*qR<&#u0RZfY>+xTJ0FjK;4cH}-kIdA^wy0H1HH1BsHOpA0IVzyECZ^L zdxsOq_g-QfG-RJ36xJXgwSt@^i%sL0jsVyMRN3eNX(aZ^+@A7C=hLQ@$E|0RTg+af1Rs`;4`UcBPKrWh#90feFOuo*7tpCRXex!(UP#UdCyK<#`Ov^? zq;5AH^1FiKg*q9o3s8?evBnWF9n)XtK2pQOvg(?$DV;FP9yi)~WZ}(pJY>=vcT@ojjiNsnh@ZASn8pjg z^wNK65HijyJYA=tS%_oe!B5IP1}o4JOL#Uv^7tvlj8EyzrLLK{kV(T*rY8#8R5$ID zxM{V6m%RFri289n3L1YfOA?;TTN=N7@Hk4c>+VNzTKsqhg*6Q)QA=Sqq){92ELaNj z)?1M!G=x_lSsVY1_h2|Oe%yMJsBLug?$Z?gR6fh&aI}6da zD|{gEpkzxZJ}#rnz|ryX5GwSPHK0szjE$C7%rbMuK0x24)fZM2IPtx|JcCn zko9^+2_jlIt~<8GJGL@OSoclXxOOmOJ?&`q1W=K+YL_!^KtSixSaNBsYRgCuLU-E^ zOjHjdkTm0lXPd-A@DyhELp0=x5~OZtO@C}@6wek;Wqfs){S&r}mZwgHFqLbZ9u0<= zF0G$P7`MiZHUL;(9*nk)g2P8gqj#2f$Cn@MD0$#I>qnQ|FmFF!+h&AZ^be*KNK8lQ zW4qw9A+{4ndq7yixH}f&PMbDep76jte{yE$<(Wxp!b>0$TAr}8{Cnqd*$%JLJEPG> zdcy9O$m(j@?z`n($xdF# zBtVXS50(ME+KVgiI8S={AeO)3zS0Oy#66Gq$l?pO_j_G%?W85n?qlHIpB-y?yl(go z;ivm!KXnSb0F#14(TAR0_uYHvpLaFTyO4k_0+qzON_LR52hQ5>y9LJW6!hkUzWLE*7qPD8ir*%lh+f4 zfqXzdtrdq{z;v8o7%Xhee<1(Vb+qexA5eP@76DkrK2yDZi{O2qhrCA~_N|fojPpX~>3n z`2Etz_si~|lZ4<^ivaJ(tZ9lenU9B%v>_z%c@)R9D-ZYY=YDDJ?4y&PT(W2KA|Z3n z|7?3P7Nk6EfB5-(b;-xtkzt1triUfUjW*9M-I+E3NH4M?KNXzc10Gg=X8mp<49|3B z8L%`8=BGWGWk(@FZ2xMENCHXP6||?)ubg>|QRHhSXJOQ!`F%f3aD%lja!3tr?=dND z0#ea2R_8$vR#&-LgSau_2l1Z<*>Rorym{h0vOOzYCzQ>!#{RC|-P6-=PSv@#INh}v z_cBuJnMX~oD}blCw8ar4G%1sA<+BYBwi=V@HF*J6`IDD z7QUXRvjm8i5H!Dqtv@@#E~C9-OYtnm92>)K))(nUQn^PkoAnp=R?e!Or|apaK|<3! zI_BE1>Zl+$gzAC3PojT)w^X}rY_rA;;3d;Jy{ZWB4H5_Ly{D+nPrf%|5%b=K<5M10 zCIU`WiymFXUF+I=IxJQytUUQp*_8*uN7bGm} zit)JMjleu2kj!(}jh(Wv2)`k;goVIpm@h&uHW+J^G(>9{JUsU67fx1XBoT5VyxpIC zE3{9$qEA6>I-+$6^23V@aB{Y<2+oU|M8m0`fkPUeI^~Hh;=~Umafi&;EF7CP-U7EG z;;h*~&;xt&SCq!4^a-#1z7pLnT7!XAKY?&EP+~+Co5QR(P1YGHcOYw=;J0{LFsxrG zMX0rJNisbjXo)k1$vcscc?FV}Avv|auL8^TlI6m0-n&SLK15O^0Bv3VLUJbRDm-D} zydyUx()jMMa8+$f51z^OP@N5XM`5>*{cvvJOmYWdKu8L9(N*Vn3TzDzPy!6Vlcz?B z&R2V+hDdxr`TDMNRx$a(RR$UY5aGK+R5PQd4`zr%AqB=hE_{`qw3O%FbF;X0momhr zqG%B@R5;0&qnGvj?N$Ye)k^&dVj^DKi(n*Ic>NgD?m!i!C`Qf&Q*`B?+wI1IugiJy z0#I`~j|*lY!-*0n$dm#3=k2vNv)w6)@`U^7$IXrC2c2dQ<32Ac^RlS)yA;NM8E_Z% z*PRca@laTZ`g#yW(*-9)uiksp6}_H+bSwJxt)oxAu9g%oN6nNb+vyI~{tUge>ml*t zu?_8HuKwW0&hNOXZy(QB0HBI{SflZ$*#H11Exw1<8jLexyJwX;rn&Nl9do)Lb)mW9 zXT+LZ{%JJ7c=|olVxW+J{%s#l05J+hO=x~Tad@L+ig+|Nz{Vl$xD~E}^*F}scnWbG zw*0Xg3wv%JUpv6JiqR2X@y#*(Az(!a;sP{=%QM!3uitO)mQRk z59+)}46sX{uk2_@GM!Ej81ug>+H~m4r1CE1diEnU0E9`8^1%ybMwpAwT}woEWQFk0 z4J}|Dj(FzWx0CaW9c6LSD8bYb|ptz)P;u=uV+ zH0YU->&OKZCc>yf01TYgthMh%_l1)MEw))EZitkPVImr=A*w&@F^?lE@YE%&Skge` zV+mn^zq!dP`>`mJ7*mI2(GI??DEYBWn6+(*rfBbpD%DeLn%9S!O;6g9?bd|HqRmmS z8d4*8BJb2V4DpOya%#TQQk8WNdwS{8OA&__F*uH@C1{mKz8F~!Lf5*$dIcXfvSq`x zp(bmj8FW(e!vOCycsal65JZi4`RUiSd=m{s=1-CM?8xBxEnUEA%_-p>6i{M%U~cS5 z)&piL-I$4J1dzox-4YH8*DgF=IDQ1+lfgg$sPnVNjjgX^>>^$Y@a?R;RChXp4WE=H z_Lp6(qjSBwwEBbhqgX6C=0K(jMW=oD`OZUKUsYyoKsvdT(In7_8`D$1IF z8?OI3RMy5AFjnh-8>Js-jM8=0jSMv{4fKuwx7oRj%{ghi0LJEA(lPw6!TDd?aw8)X zGcyZo>;L8)*V8(}*EZS@cPYr>vX_^)ukSymmrR)t-?!gM|FZr5Yxw;?nRfqU&YhD(`j4~Hn`LF>ii*nW z>Kcagzon(6t*yPIqvQYRyz@W57|`i;V(;+wZh zO3QAO%kNZF-Yo|qt7`Ap)jxPhDFG=uxtKujh+>kCs;aW5iXLs~>mL{#A~m(LFe$hg zLC7lp6CU1ylBp_z6VG1JS61%`y4te5K?>jBki(CDP}P;ar?IY^9H@(08qKwY)$ zJN04J=&ed)ZZQ-Heg$CszXJIN2KlUTC~~ln28m9TJQ2W6^w|GeRxOSf($o#`4B*%A-{QA0g4J9WYk)9V(OezF+(YW;&~2_x*E-#6LPuo_qRpg&1q&AhlnEoq zi{vrC19TCt<{oix$Ug@-^Ci0d`}#Iq8NoW;fhr&X7TX{LI5ANT3-wk;0w$;-SxhE; zfQDBFr~w8E93|jEOdfC)-*H%Vp@s_wkgyhhD5glv15%s=Kx-#l@sohs2_gYQ67di~ z3K=;l*#X!%=v7u3tp!Gp86^OQ|8emdU{*$Es3_%>te|j(3Rw^_MJkXm06}AdB=A83 z!Mv2o10MiG<(h1UazGJWw9w|9bk>PWop|P{=bn7_>F1w-1}f;FgcfS(p@<@aN}`N5 zy2&iH+>*;K0rc`qFvB>i>3z!#(abZ^OcT;InGM2?T$`q9S~)JN!;U-fuveNO_NZ#B zY5o8tP&xz|gpfiEIRueJ6j_9kMlX4!k*tH5gpx`uIrvgc4${OH8ePS3>$b1x#FI}z z33c5dM;)dVQ&2bsl~hz&g_TxZF)N5zmvMGhT5GjM!&`Ax_yq|sP|EGVrmUtHUjmIQ zNMM5%c35JIHTJ<{kxf=v|Gi(8D#&KXc?RNqXNX4H0cw2V9Kk4;GTn==6@}e^+u0@& zZVv7ynQy?!Yie=wDaTxMFlB^BrYRTg$;#FFxg)29Q98$3~Z}iGKW1=O2JH5@_HK2r{7{gAN8A;e_5)cwvScs?p)cAB#w$i2*z? zg9iz8X7=J|wulalG9Hp0Ave~hBabru7~~m4a-)WkNUEV^*8w=$W0W3X+m*nKw@!(b zSZc}TBVK|TfS6NU2mf2oto0Br&NX8n8kF3sKQ;3L-%YD#*hg79lTt>5IYw zZ~)G!!CFdu0s{gtfB|^02NzfZ6fh8g4!}SLoiRXL$n=6O4sZ~|iHS6fAQ>a5K?aYx zWEv0H#!Vru|7C}Off{zGM285%k2324kFLTw14wd5jbB?A-5nB`|w* z>XX(P;scb^9zm3nK#Re^cP_AiFjPhc)o6<}xRSyd$PzfTq=96*Kube>z#}vC<)+Zq z9{~I(K!u1*;*9u^h7f`WAFM$RoS=X(xP%0FE5TV3Fv8N1!3-pzi2*#&AQyPRmD!X` zgSsFl8gOI=Bsf4!tR>D(vB*V`n-L*mqKyPxrJbfUW<(^?gej^HB-W5gsYHM+$%qn3 zF3=`6fzu;2(BxPptLUv@m!&OXVgVDV$h^i>4~k;q0J|eZ2Z*ZETNzJIO^qrkz9-eH zTJ@?}|IMmax60M7mMwc;4QnF0C#hA0Pkmx_UHhEzK2-oPt&G#3I@ZxYQ@jes< z0MM%;K4J+9NoD|U;6Wx>z=at>VQ(l^21;2aBW$Er3-OvLAA&20b9{t>pu&V70O2q? z@E`-`kwuJXgNrJh#~4a57PhzrE}W!npbQqrg!$DG2Fk!G83Ke0>;MWrSY)N>f!g{7 z2d$wQ&HZF6C}1kB5>9x60tT_!+SuTgJUZ>j zO{vi13^XX63WI|x`iPfNdzLm3_rlltlN3u3CD zp5RJ!qWco+qK^YWj5In4{}Sl8NZF%^97GSU2x)*Ov{31uq=qP2*ibx`-62Hqfg0CX z1Oc^ijelndpb8au=lcNskjgvX-HygO76FoNECQ;&m`YDY#5_VrSvz+A&);a5xtYrqpS?#>3wSsERp13QY q2^9zcA^8LV9smFUESdm700ICK0DvAI9w;a%0tbu(smtvb3IIC*w)GnT literal 0 HcmV?d00001 diff --git a/external-deps/python-language-server/resources/document-format.gif b/external-deps/python-language-server/resources/document-format.gif new file mode 100644 index 0000000000000000000000000000000000000000..c68f89a1b79d143215c08e6caf3a46cc70d29de7 GIT binary patch literal 66169 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

dQQATq#F6kms`?=H0 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 literal 0 HcmV?d00001 diff --git a/external-deps/python-language-server/resources/document-symbols.gif b/external-deps/python-language-server/resources/document-symbols.gif new file mode 100644 index 0000000000000000000000000000000000000000..1d9601d6df7a1fa7d4eb93812c5f7bbd0cc7f2e7 GIT binary patch literal 37353 zcmcHA2T)TDqyPDn0x1v(4+=;PMVbgfK{|w9h0u#i6A?u)6ai_54$^}3B7`O&E%c&j zC`!kGAgF-!W&inW-ZgP^0|^@wiL2%^I2~CHeI*S&te(A+p@pi6jhd;Qw4w7wvpcd@ z-j{6e$zKhWbg`B8aJt~@deQ%uOpwRP*VUBKFjO!wRWUJFHPg{ive8s@)K}Hi)WqQo zjE!-IhK4#?riR*$^zJ=#A1@m}|0_ZFE&YS6?g!ZgU%zg0>$b(cd)KaCzkci1t)L($A0MBfpddx( zNF~=em0O9bcT&{|nd&}|t$d?x{bOzK$7}c%Y2AOK9a5$HfD-Bu_P{Y*Hrz)(DMT?X zTq!GBr65tIFj4hMidse5HR2;(Vx3+@lYUg2LEH;mbtbMROQZ3zMhjW?-7Rh~KZguF(dqIRQ%F5^do_>580>b}srVeOtuoxU2K z0SfV&akvAXXd4pkWSZ`7^O$h0(8s>yo>O(8OTz=V$g5$o_K{&ukmxyUoW5GI zx3aVSTf=V`7KL=idiE!HkC5&~L_|D%_%JOkEjKs!1+l%dDzdpbp`#PH;_^`ORxUsRZv$ON(&mZ_PzzlHcQOKPUa8~iFeU!rP80Hx6EWNs- zSMeMdZ%_Bt7564%G#_&7*O&CCikd&Y+FxHfn2EhUkf-19WH?veU1Pexq3lfoiw}~= zps{?kST9xl+CXE)+cJDH__0CL(~0oEif_*hG*wR4I(9$gF>J1SUFr7rsb$tg)yEdX z;=p6WmYSJo?%Nw3ANFcKy(B^yc#T>&r#fO;x4*cz)-Cpu1P$}Qv^c4TC^7GEKWS~y ze4VBl&wIJOas4gkjNU5$VFjHq>fy@ijr z?cyL8mSo)CsJLdgV#3E0ka~qp@bI|va+D3OJ;wEDdLU6P2mp!{0*6F4RF5q-D%1}T z5RMubiZ;G9&~&(LHBaRPP=lwleQ>blI2bi{qirCu_IG2&S6qYeeTn)(*%pb0vDfFm zKi?T!rh#;r#zAb~L#cPwd7gj%oNBzJM2h%aePrISd+Ez&H<~$WItkcbe9~nu&As)S z+y9G~Uf=qtm^zbhcOs5M>etqQM9Y^817f|?sjsCb?`#i84ODF#%PfA`euEQi-KL>- zxpzkOM6Pj;8g*Chyv6JC*uAy5es*`l<|fK!;wo45?xbVP%&AGsp!0k0-O4VrzPHG& z-up=CeT?~N^z8i4nSfQ)#Tg}~V{FeSB203BE|T4Ie?C^EW`7|;?%Vz%Nmue%eTYNH5bK?zBEpH9(`?HtvUMk{O7l$ z?^Kx7ugxCzyT7*jL~4Ki7?S(`Yn!Gk^?PUB`tI-D=7JH~FVp_tRZvqgQh)ZBGVlI5 zSSzdjbNHp@`=6tAcZYi$XUFdz|K4A%J^r)5{q^`5U?c-DJt~-UlL(~oO|0og$!>lR zLr*(sFl`FzUyBN-*Cf-+^>s1@Zbo1j=Yi91r(yE^3_@QJzlr>b@OHuj57Fq~e=QKb z^ECN_at&ZRqvu!-H)C*&Md;%gy&m)vf;g-%oRvcAd`e?RS_BlH`aT)!HiYL7q0ZCo z5_$vzx8fZci#dArUPt8Y3>|nqun=#!jdHbN5noY=D}+^qW5NR zD$u8)+E>UNQr^d0z2wq0pf_mu;YUX6P-)qSe7bB=6upT}x3ry2xa@c_>McPBa~WV% zzBG2`tfQt%_^6(}A#3Udz5QTjHFB~lFsHN+r7{JT!$Jb; z%lL@PK0CMY(VV;GdY7M?A=YRGxN-5ns`<2&`4il4r)7;LXh@UzCjzy$a_q5U(uO$W zv?ezUct(?r=T&!Ok_ex|jM$wWCn2(*X1vPz4YQvElP?Z;Yh!OcHOb%5;!K+>d9~wa zd683(6nLs~m!yHHIrHj>KcfmcdNcjoQ=QDN@w|)G>zC&Z&}}~&YJ5+N1F^`dckO#k zlthnPEU7xe$6aDYCIR8tl9VeC*{;`dR>K6vKWHe7ccYBlUdu49TmCxZkHTX+HCzTz zp}XS>RbPP1gIl7!ypC!%6p@=uSZ-^{P7qGztHR5$D6S35=FP;~;MH?Fo!^!sZTs$~ z=dC3K?z88+dci_(X1a-8ks*ZBy=czR=~{-@*>Z%Z;0!S`TknJv*GBc-}0&dHJ*5 zN4tTd7fm((!=LSAq$gi6HB(|Pe_;`J6?kRbT%S4or9;nJiixTbdhP9(+gFZ0OsV!Y zY>$=4Nl1U3V`^y)>G0?Y#xN*wx3o_Ve-q6NlKSM?@_hC3_x%@2QmeCfJAMv-59QmP z_0}nT2{Yad|M=IOo7jay)W~ME(ys`(RN-GYer`Uz@@oN-5MVj-_|vZ^T#Fdyw!YI( zwo-C`Er}k(9Q(~jeq=mTc0Ko?ZRn=4&&|nSEAnsJ?3`=1^N)V5Dj&DeVkEc8tiRXv z*xN=^M|PfE3|?1JZ?z#_0P_1pv8VPb{MC7 z_B6yiuCP>X_D$aj)KM*$7*Vx$N%E##E?|&*Hs_GA7jtLuc++OYd1&3e zg&qDaHF{*bvJd`x3i~6yt((g0K>J%~J3y;Eovrl1OaSQFiUKjqbEJ zqb_Pn_uu{j`k05DetWsz9q3n@zpyGFbD5ds&3q^x4tO0Ag=$S{hGr2np9Q5ss#!ufY2x=s$wTCRU(%zTz?;Ja+R zDP#g8!~89SAQOQrWz5q!XFgrtRp6X~t4RnBet|Jn|-V$K}q| zV7$~mm&7|W!cG4?I>5!sfUew?&)=AD#Xx3X@b(^eDSPCvCH;69e^Hb`xU38XP)Xi7i5HD-K zOl!qu1EomjWi)Bo@nL#z!1~!F&$CGjeX&NZfnZyvPJaCTUeYsp<_iGO=LY(YWnL#S zy^c+w;E{5UDVv*2YlKH@ju2(_n5n5p#L`5hsmn|sYy7095;QjaST8oZPlU5I4B46F zD`H_UjHYPC^?Dg+>RBJSB^z>@dldNI8jHa4%y|@NvH=zR+mXzM z81pGwr8Si4rX`P&fmi*6L0-3!R@4KuZI z&P&m*UP6IE&Nt`<8Ic9&CJgo~`~xTaNBT3)l7S6c=vVw>pIZ=WIZ#at-KH{q(nk~J z@-N-CShhu*m2rS%4R86LUv6Q04Z3)06!l2YMJMA7;Rnhp7Om9`mDENXVq9izu=W1t zN+kkn;zb&jJP#%?%VDpovhGN^2ElDObE#-44?@9N^}`YMGvoU;_y z$%H+uAb$u=_<)WZQP%HF4ZZPR*AOHI@xE-#BZ3nO}u>e%8Xf~2{>TI8^QtYbbZ>-I{r#Zh>#)bF>~ zoN})h|6GfJvjn%+W4UV2b2Z3Zsk?Z5r9s}EBA45soLj5(u>tqFMvbdcE2u{EN~7LU zwQg>sQBbwv$42~MnF&{u#j{LvC0?G)ddp``uKrE>Z?l4GOJB%!p$zZ%~Cg; z50;_rPn!u!KK4hTuf9oMK`n~@O#o|Fz{eKt$umVU&7n%I^!`m>Ew0oXv_5qAvL5sj zJZg^TYBTY_6Mn8OL+Nf{P+JazclNWk{3Am8QCm@vccD`I69(_np!TN>?Uf(fWis1q zxSsu{e|EaLIEV$TOod30*dZj~#nCee{xtrf0neu31Use5?DWx%XK2&sZ^G!*ijtnz z<<-YGHX3S^q1&D6I9kS&-*9#R&I zK2JhcQIHR)=oFw6$`7r>GCU@NAzKiAZU!{~P~Ak-p&1G`5n@=hz%Q|H?m?@L_b81) zyxVev!kh6nYq>#oik zqMfh^W|Bdd__2Ez-Mo}YWWMzltcnH^*o2)2y6G4J$xWC96p_8<)3aWDH<-M=ceS#1QH7oeKe#92W+*NHhLn#>Be+7a$92~<|RgoO04V* z?Ak{P{_Ky22+~oNnWPbGZ)gi;|c;8Ix!#kNS#{>GW#kz z69dN@!67X0Ybv}K^AL0_;8+S0PC@(5Ad-nE-xW9w%>c%tNq7W(-7CKHaod%zBv#(8 za+J!Hj)jHfXez`(=21&Dv6$h=Ra|Utxmj9TMwPZmi59QTu>$&?-i7EqgAhzd_E$=7 zVw28~aqF!KNdlm-*#+T;S75>X0FXsMz^UL$JPkvEFq46JA_BkyDrhha4X?z<__?G{(-33CJok5<~+#b|ACyG$G)fQ^zwH(4(I4u6||!1|SwcBEUG1zA{4{W)i@I z@-YkzWH7YwMUc5>wMBMSPhj~@LE*7)8uGUJDLZHJfSjCGXW-G|qv}o><6fiKnMdUX zym=Mut%a)nOHmvp33_kvo^@ubyhA~!nX#aIu>c1B5h@L!u^>KGG&B0MDnCdR4Qen3 ziDFZ`2hry3&yAii@22SB4a%F`v%7wyd+%$RZ=lT$G|q)=U~@OB(_P&&k{=xkb594x zKKwdW^ObnRZIh<49!p89URVq7m)3>tG}oQkA}n8L>K%yW(mkWQd` z&S8`cf~dp7Wl)y*E$o9k506<|jT%597SJv{GcN$VAkb@(=yx6I07v>AM>;JuOuQDf zi-&0u=ylQC_yYD1p4^wOZ{Ni7?vUsKJfKUWzeU;w2=v--0I1WpANhxA!QQQu4Tmec zyErIB9d!=?hH%WiIL2M_E)$vY&jh2}F~c8Ols0)U(&Ti-$gI}&ZH))OIEnt!@lHbR z?%BI^J2+UqHFSi=81?c%HDx1meQ%Hoc;T6~9k=fifET2nfFsn33h?4kUI4&LqUWUi z9Hbt!zUhoLbus-ac8L%5XPE(#vb_tS-ja85-yKHCKeRD=yO{kpzTb>an~K-Bwa6eh zH8dv$M1SlBaFKp57J_(jzsDZTF7aJ_=kRCaCEIGj1x5hY@$%0Pwcpzg$3YW+_6m-{ zk;jLhj)Ng+7{DlGLz`2NM4Xm%nWD{W#F0mP1&`vlb>$x;Fx~NOy*G>|$9b3{* z6SJ&g6eBGgW=Y=|DY1RKayd`o-nXUqZ&ytsCAE1m$niDP68&_^8z08k&C5;YkaTTA zgA+_rE6#NZ3~Aoc;Lj>y=io<&jc`%=5iWw$P%EE0f z!dLel9TH&_iS@ajIH$gpvnEfjzW-s^!}-{y^U-qm4O*dgvhX!Uf@{Kkx|Ms5A9mfR z>TbNrKaM+GfJs1@U2a|e`19^uXB4c(L;7wEgfD>k=Ir!=&)U6sYh}mXjn%dHO?Ovk zJ63(;wK{`D9A-Ctu)>=d_Fvp;ai8%EL%fsB|foU}3_SP59WvtYT_;E-L8&326VIa|9gfxgq z8!R$7-+ju*D6dsZPxiuF3!lrWLqc!`7-cQxvf}5))b3bF+&9l1}7VBIV&q?%C z^Pp(EDSlX@d|yOF^mB!n?%-c~yVj0_Jq$x(KNf}tDy#}E3wdq&p)83tt*glB44Q6o zcxylGz2mdp=HWz|fM3hmQ^hI809YRPJ_^krDG1w~YbJaCDBOUA?CtwGgz5%v5#MD% za7{Bi3*}K3Hl~r+pm5u$(^_c25oTefPj_1TuddhmLGRjb+5uGu`@HUq02K%_^K`~2 ze_>f&RDyS{=0*(hmyuOA+u9uRgEHU-VadKma|x$x&Ze+PIz?G&ne~I5)PVpZ-LVDS z$tg0jtFA03=xH5{3+U=!MAmF^tTEM8&|#8;y4nPmop-k;Fy5PD<;)>NTleq2nAjF| zlTf5Ox7-&Q2unu*98R~ONwZEdT4wxkRva5rm-|*NMTZ+;qDC;QwhNadNRuyM2tdQ( z^0$cgx?GG%`+D)+5ALvbxoNOSupp03*uC)5um@}`{vx$k3kQ|5nmN6g<^u9EE6;TJ zHq$)~b$quT+Tr)D?PbT5REUgCF}GEiWn^jMI}rcCdG?rySawF~RJI*;=V`&NJ0zToT-9(IH5fK5UVpy|qaU>cv z)l|#+dCo_UuN)HQGp5Nw(|_^(-tT=2n2{nH8Te86`)Ze1QsP})bWgq4)6?-5NKSJ( zdp;X&@Xm!fWDVjcQxu~h)&t5_w$@mgYLg}qf$JRMUyXI< z(phWYagHKWvGXbi(F!}J1_^oHTqx-kg;u8`cT^Ev z+$EB&aUA6Z%BivX2hxV1$O7#Olj)x zQlP-TI^Q%+(_qo6moCi-4#RtxUayGsAc26^zE?Om2H?USL3YhGZK)re@A$uHa6wQ0 z6@5gECon~_*YRlH0RfZJGIDJ&bx+ShD#M-G@bnwl4csHz^wkx=mJT}HZR?MA;p3Mn zpMN8q5YAKi7&c%xZwBQ1#3c2{n`oq|>vaD6FgNGqB0#>k2B4xsTar_FtSa9hfLv?du9LL%GzfTiV9~;f(EPTDFXVoXu z@rvf!{3sO^&^~1;dFl7V=}4L%h*MJ2BlB5&`PhEJJdb4N=^}f+)%U`%v_;F?j_1!si3M_-Chr>0h32K^R>5;Mm|qRI_RW~jph|oLERtA&&D8r z%wH(`&;#JSa(q~5{EfD6ALn`{$_6juCvEvx_6zbu&Zk0z@x@*_X2R?XK#re9!RkIR z>nieA0y7o8J02sFNr66=79L9py>R_ZEHeZ`Ey(^R3HW)T-nHL@yDrz4I~Z+zdRGrR zgLkKwFmi2owdT_ABRpi#xMDNNNj`2NyRKfqLW^DJfN#y)NiO^DvDc#om1L$|YcymY z$6E0X4s{vrsxyTJJC+>u^^TM$^0=g?l`K#B5!+O-*Ea^*D`N>~fIn+uY|Z+5sn+!K3foLM4hBrJ7LCNl@SJ@; zi%7?v6NOFvtmpGeur)rD0wEAh=+SVga^4iiIa$F&7s}Lc)l-9Mdt8F3(yQ_q{I#^B z@9{s8@59FK-1S}jGR6-%?^cL^ebZh%X)<_K>DB!=G5Ka>_KbICr`ki}5?mbbs&+!hw1;*xI?JktYH-!G)o=p0+{@?-q zd%oi%Dbk;V;|Ir^Y5+I&2#o_PlX7)LA6d$1v)wMxBE=_0xCM`yJKU6VwG#)Hx;6IiIWlA*ypvcec>fd4H+b zZK`9qyK2xH0?J+GSPh}88c*;V!ogjg;TmGTOd@$2=Z50MpKF{iiIbStkV- z6B!~ekNw|q$mM@5B9lFDF>Jqs74-egdV}V3iOgrWC+h1 z%Tlk8pohV~WJslrVb0O&O%a`t-%RK)Kezi|`W){`TpPUPBv;1wOncbiZy6F`l5x~q zHuvJi^sg<`{WsJ3)!v{lN9@hji={j{s$a2kwabH97mI&cdt%xi9Onld^5uQuF8*|;CkB!@PJv3l5t<~Q~Lf8GbHWw#7OkVzZ_4CK}=ayS9)k1z9(TQRV z|D5jQAwq<+$YG4Hqsigujmf!44;7C2s0GvVLNhk!wL)L6=vLDhz6|;NSW#iEqBse= zjD>ihYHA^2yEC>3qP0}Mn54Y7wwR2g7h57}vE5oq(GwOEijtLCUrNR6h%Kj?DLO8v z+qhONXI%Y9hKQ|Xxn$g0$+o_rznpWYIc_DF@LFs&&-Yz+X^!wx#cF==-uh}m@CVVq zWyn+s!ioY~D@yoNF$xORYPa_x30SX{Mk;PbvUMr=yJ5#<#5W2&If~14n9_VkG-vLS z-#BKyK1MEr?37cYN~d`^qfQs^wU-Hw=C!BrReAeUc^?lvm574b___zlQuq^P29^$9 z$;{E-8mT;)-C~s4)ne7o@1&VC%a|>lc_q_HG-tlxpr^^K^0vN{rS9|Zlw{R?7ik*r zQBFiM8-NXCez}@qA#1BH?eFyB9_$NkdJnoz&oq3Q0O+{-B5#Aac3Y)~FD~b! z8C$kguWNAa!dYwkOvg2uc{~^+x;S4OMbL9yp1yL2?J&6bmBNAi+-(KBtZi{X&wV~o zb(XP&j?V-_iBVmVd7SK}?e0Z+$(cFK-8&N^exd)evS7mLU73`6#ND15pM1~pi=M;2 zo5zT!6wY}iwA`UhNt9}kW5@J-Fp-?h2gs95Ca5<$WIL}!;H7WaqHY^r#<4c5o4s)H;u`->@D4)=cy zN!7Ng=6z=Uy#qYgYw#>hZBz##yGgG>4J|5d6U8hZ3=`ZNThYSu*Eu(y>K^RKs9(~W zhjJ@$%hl7us%M0qc?ee(^6^R5JXAs3EV~INDzxZ#7=j6JzY@EbC{eZX0K~ZP>FhST7oU9bW7z>X!Lz%}I$BBN#VVE^x3v-YnD{CJ5V)Hle>LTYzH%Y!=xU zkbcUdHWVA7S#S4=e7(HN5AQff>cvbu#q6L}JZ zZmtK|qLt^JiRO=1Gp^k##a2%~apr8$_cM5MA+vwTHBkR@Z^BAWp8oJ{yX_n&&L@{z z`iDIOw{zzh%j9{?A9>|$=biDwvBhT52^MWXUhoCr2F~XKKD^Dt(7H;#^&h|Sc-K$> zOt`AfoS}tp)Isttlxu9a>N!a66mni!VjY8yK6I5R&=OiuJwGs-6u482K~?DK8jL;4 z*(njdTw!26FqYB2Q@SH260(OD6UM`#DHoXi3GJpR77I)59s}hjbOjIJp`Hgc8^^nT~c$nS$~3j#s&CmT=*@YU4V5 z2R2O3XSfU!m7N?`j5BJdkOqC3toaK?=OOfH|GDsC4I%e8)sE9hvD%>Jf zVczKI!8aXAI@5E*TKS@th`rg;T*qD%bo$_I(oWbKtL9q^oMbO(h|g^kAI<==)}9Rsi8RM zMFe`B8LwbpDYtGqYf&S3O0#0XTGGj;1a+S8eU&<`{3!`j;)RRDcDAQonaby`rvvCL zoqBw}Wb$eLA5nJxh)K|0rFdQ>wyUhu%8{(7IGJ)20Dx5VBZHop${LT90&)j7nbHwu^oy?JwI4HvD;4j5@ zzNI>=H{>kGkS<-k(qqZnm#3o1RL_#=m~?!k8U8g;xxp{j5y30-n=ynKeU6jwXlLd) z^z(wzOQp9`Y^{hdkJoLMl-_vVh zr8DRLrF`J1K)7Jgb%?VPs$c%l{JZ_b<92o^&!)R8%a!cHS_!{C z9KFcNi3;Ii^zO`**VuVwe`>JqcF&KvW4RuID{=#8kKkN++%dI233n#8)#Sp!4{nApzSA-P?kiP3m#=!ZQ} zcNw%1QLn*|JLa^)xNCr7Au%O2K;KJ#&=jIT3zuxAlUxgzr?ALj2>MQ7d6E(vj!rrY za)lZptw)ChWVJ0t3wBY)#h!GJ9GB73ar63QEg}yfeco5+j5?QV2J5c0L1`LuXDYK^ zIkUkU#~0cI*MR6(+C=>@xZ6~;QnLip9BhV$a&YAfrlDrZ=FO3Yjz2}cvmCg$pbw~q z=}X+t#tk7XF+MgihGC$PV-1K5P2_7KkkTqb>Jzz0j>a~{>}?cw=*7EGllpSdR%AD*YPZybAAA8Xd=EZ-auFKnr4py~g7%1pM=-3}e!S#D-W ziSKnY!#5|4>?hDT6365d$88ed1td;oC4Oj4oSsVL);@QpG+{Qtq;U*nRTQ@$g zzP^v2vpE+sm9*yzV8}Ahgp*H4S?}-T4_lLgQW;23?4MYZM)qXLed8|yBxDk1V@qt}y|6l`)H>;K0C&e@ zG&Gc^k@A{NSpJ+XjW|4p$=OWZACXSv*-1rD&!tgPH0iTXndzq+ zs+;_|9zfaUuqjTJ3b$U%It4+)tLBhTv0yk$27DBpM?+SV5Uf}YLh?y5&SW1Ae)EKR6=Q#z)pl^pwq48) zI(mxZx~=iWV7?XBL`!{tF=yvR)>RBTnBb9hgSTT{#wFD;MaM4AGPguXI&MEh;5dfa zD!}}jZNj;A4k8VyiUkwr!0}=kz$TbT1D_`&9|8a?EnAQR*+c;Q3gAmrNWqyL01a)z zLL~@@LM#BoGCZPy)ixmj1|&^D=~n%O zbsS7}I9kBhcr#5sv9o)N(u!mjP?uOD$Ov32dXxP)L_atg;sjxF4yL&U+eR|72^{o5 zWuW(F>X4BnmV`JoD;1(lf#;D6YS3_I61tKM7eE90pd9!Xq7Z=M07MfRjKDEG!h_hu zo_KmW!ozaIMc5uTD7Y=D-Fp(2;+pD74-i~k&y?Nqyv6kC7;kWX51KM&^XdunrDd4I zV%g*F%#_HRDfKsdz*<`AXn#@C9*aA)knUdFDF_v*;#m5lA5ud_#F3HLkU#_tSwlf` zBLF2r))!kcoFz96kLWQdOD5->QbhaZl+l`1Q-vMI=)-7&9>LK?ea%IFx_5e`S%&ZX z{~AkswWqvqRz7}m0`B6mqI0I_hxvl5;9*w$mpbH+Y;-mj9&Zajsk2Q6=%h9Tf*%}5 zL&B*ngNFzbi3LIdXJG#h!jA|DcBfqbcFvx6Wxuw|o(V?-ByXFh%#qb#j@9bElP2uQ zI}^xcLw_?oLP|Na;#D#BTntON5AVV{HuM;m%4inPb*^;Ut5S*pDB{3yX?P_LEC2vG zBm|rWuBMgpQ~$2P3FNBGJ%8jXU__A(CTb4%D&6k&GYTsbac6?RvOjl(j`87|ibGqz zOE*^tfNLvUXiLgao*M+gFz0*~j7tsyE zww|{NW@nI%J&rGGW7BOHbIuSqc(d4%56KgV4&6LmbJUn_eyf_xJ7sqZU?sc2(O^hC z8Ulb=H=7|_z^@~Yzer$~xtFI%V3_VBz0t7qwtuB*p@)mYe9})b$Cep{-7owYW-uCd z4w24~ZE#4uVN-5bF_3v#)a|s`xgfx(l0Pa#lTP z-W%Heueke?NUuYt-zCtU^x7Q)oelk+#d%OzYB=%MP&w*i2T2)%tw zrjKR>-0;1OM6_!#>{>$ivS{C~k@T-JxbDgiACSymV8U-Bjjnlp}o>|l-#8b=qro5-hp!B`yquO zE)0&#@eTAO-(q{VuJUbj(=vMiueo99V;Zu9#yCS`;z`^)qPhCqBcB_+(V&;+br0|u zWi3jk?;RZsZ!sd?muDE$u}SE68yhG}hDXuFJ@TVto=PQ(!H-W{L1f>u>5qyfzSaKn zNcs0$9M8Ch%DC3Gah(pDYREXJ#^~3QaelM6uhpL#U*?NRi&a*dU3OCK|ns6TGb_ss>hsA2cV(j(|?`Mm1T)*GlSD5q-nGAS58Q3uyJTn=3USEHh z2Ld$doj_DFWV#a+NCoN7qm0TPe~rEGG<;L<1|OV;jO}1iokQl5;L~ArKZ$hA&%+{8 zW!7!ZIbA-74@~~b0)PlW)-X#Pv36!2xbH|B8?bhrNQ}O&6<%Tbr7*jO0N4bxt71p zX65nM#6+j+2}b$%!-YUK87@RZ)DWlQC`d(e_TC}z(-wXn(|Cr3X%CP3iAU`bQ2?4L zkVuEjhe5(%NXZWX8TJ#+WCP5mr=~AvpnEQOO>le?((>CG=2o0Trs{)_Lf$_lmp-H* zxB6M;F-+t{x_1~RXbLQZcJe|5d>%Uac>X5|3II#a{OO)sglzVfcWw(p(Aw!bNHzKi zE9H~z?E5(EN7)xFa(_UD*H8-t;H?VN$~Bax{Sv1nn}>ZhMm62LBGD-kKe#nIT?nye z0t6|a_BtRnw-*-*%8;eUJv_`b zWCQ^yiJ!_QWx=szhZ+_+1J z7l{SA=Ac4y}b-zR%axrbJx^SM8N1O%qJZ^oQL z&@XeOd{lV=d;qppOrY%)lnZG}NsS*yhTcEDYhL?N^t~06=FW)sju<%IXwE)v)H>@1 z)AtY-uQ+DpA~4x3r5t9L6~*jbXZs|5widK!@e+mp{-YTHT7YeU#DJ}ZPEr^?l2K?A z=pKtEX@Ef^Y!Ub6Msr*xPI2D~;|;BJMLSSTD&VCIWbe+jzJ z864?_jyr!#GjADEP&WXeox%Vy{R80XKT;U9<``ZOj|xqo9c0wWZy|~dZ6|I+Mi~}N z=ogsLz@1xynyw#Z0mNzH@q5)nmo9dAgZi|iW3xRB{t}ng6PoY7rWJeurcfDEAR_FK zx?5;}%aH50z2+`3z_b6BA#Iy+FC-8T4p07)`Pv`{?WbSeG+tG>i%?oyq<7rltvK8l zRrZ(UmkZ&k+Biy0?Y`vkp?O^qz)ea<6Zl*Kybc%W>__F5Yh)T@S7b-v*`0d~RM~5Y z`=HQ+Jqea8gsmLu;^Bm@UcQ#mCPU24mJAi`H&tz$D{kWz*Z(jgiTApER-RYx^dSq~Jjl%Bs?s}UC_ayxe|qi(Q;VJ9c- zqx+TGYiQ}uzt^7o7-u}SeA^gj{wHKytqDGngLY7WrTus#2H-F;d1I|z9xbz+Rf$x! zF6Rxo?2)n9SdRg+8x{yi8SHqrpW~VPqUySY5>T&cRQH`N@H5~c`QcSpk;IiZ#jDlH#aw*06(9! z>dC_Stgt9XOhi!h{5f$6fpZrylJe&zuo$fJ#fvhRF3Bq^EAw2```j5in98GPPD^5ET^_6B8RBpOBnPdi3Z~W@gsOq_(*D#9=>e zY-~K4(Y}01{bw0VqtQ-&RR90oV8=wd@Nh5~6cNFTj!#HTN+zW|N=-}8$jr*l$<2G5 zUqCJ_DlRE~QdVB^w1_u0928X(8x>RYu(GwS{n_)57cZ%uUEMvo)io4weMDn@%PZRG z*xT`mcau}^(Y>+#gOSlA9~PIES60{7H}a+@JyRk3jb6MZR*^hll4a{t=-8sd45)fq*%SQsQ7 zn%%a3L=6ghC+ z&f8Qa{3`0&c-KNWUL3HTkgbr{@o*m}EgQ{{)I@1Lk| zJM-xjs{|!&F?uT+ui`VgEF(^azK<&p_W`Em6S+KTn_ReAAX-Nr4|xk#iAf&hk0yBW<_&C=O#$ zt_K``Yy9^)txk5LLT2m&5xgbk3lAll*B0WjuSFOC+4;(^{F|DCyw7`V7Jq;FKXQ(R z)vbS@a|{E|a-HOy_5UO1+**C?@2txm5%71;A^tP;ycbLR8US(+lzch|pxqodkQ)Td|8FT*pwPh|^sj|7X9z(Uc z>c~%rTxkCM?b+rf15bWgIE9W~eA+PzX?lBrh+)K%pO$X1-P!Ey8##wVSx#I5PXAKP z#xY&{bp<$v*u$kM=a>l6kj!xHgv~yoOo@1qni2X2otoAy0LFk30Kr(`;p)TI;#VO^ zhao(?2k)E^{)&-27xijTep4HDb%Y#+5Y|1v+er^KRZlwwWjPB|#b9H>>d?+G49|`u zZlq`IBjo~4Elzrjo$qVh2=R zFq7={HZ4Wh>ZEPJp+SY79;I<4~vi-|=(e*-IYe++_hT>60O zB0f1s1PKzA)YovZj=}UcBS2ZAarhiZcjtyy45aO>$1QqbR)63oIRC6JowBsLdDR@T z_fBn)!AA{-4w7oc92I1y&vz89*P|$lfwPGM^zADkOkQ`M-hjE1X3eJ4X|+8&$vN!CkPXaf^Szkf)wX;&WRb(4WNPIazIujiV#_Fj(-}h zE|)(;y=!QA`4jYdxL9x}D7+8#vu5=<*fETO4l{_MS@#$R)*oMHfX_j(xoZiH~rOU%6jJJ;Q-87D#ku~_D+I)D=hpIpk4wb#*ia%k(kp$tE}$j@v! zctk(*p$n`oS}l}(s>j|4Lnl@Bzu0^4uO|C_UH3^(s0qC(p-2Zqkq(Al1Pnz4K@7bJ z8j4C2La$=zNRa^2Q2~*v7>bIB2sW_18Y~F-iUE|WavpR}=bUTpJ@y*ojPuhz{sB7F zF~XhubAPW(WnVtWt4DANgiW7RVgA(J`AXPnxm{nYAcxR+E`PMRfh-A z_jlmge5S_+UGIen5ZNC_0NgLF9+&#f2cubl2>Zkx?t;ne^(X#Mb;&x?A`?|Y-5(4d z)=?GBDLJQX7PbaE&2{~-hfB9h5$5kYq1Bg(HSLtw0yhXSf$XOcwX=4sHe@JkUNKr} zmp{b4w^(VK9=p)d=&`oR3G*XD#Lxi{h5#H2-FN(QtnakK1h6~O{)~P)15Tw5JVTs@ z+TNCw#INhXBLyJWhRV54)6`}7@rRCt$lOjZQk~^|8)KuM@U5Sjl3qn_ahv9R;>1Ag zwq91nl3v`M&AbPF&(LwPlm&mNx=;38O}O6d3sECk9Fft?dWeATmlx99ZMC#9}Q&>JUqF2jgI0}Ao6ZbqzgPde_ekMEP$;#Bd6oiJD-5!J!H6<+#s3gMWK?J8LVBhp^kDZS24Tt%>}($;fkYNv*MgE6{wA_YtJ z?Cg4QV*iHhZs0krDrhUr}_Hgq{dsNg7tZq zV^;>pYHzG*o7$PEEazUcJ6*caf>jzxn1mf&?OfUTJ4J4D@-MqHKJncip~qtWTH77i z%}!hl{@BO#jXSe#P)bK0p)&5F94|13Qwg^Elgpfb2e;aqf3Cju`Vn|^J9>I=f0=&OWx-B-t*{Mp zZG>Ck6E9=ywXCP3_IBz46eL(c?t4epN(Y%$^nLOC@ySbT)+@&j{x!$@;S2fcXL-rV2WBIG#;T;eJ}YJt>X@ zi{O}ueJFeO_HA`%0!*Fa&?kXVYSsPg8dY+H$~@!eRtW4NCE!K?E|&xWIfvPIV%HH6 z7qX!ZZ=zJmc2Z$=%o2jYGm`k>qx9o7`?Vr~8+$BO-FfCxl8v0az7S>q2w=&G|8dy; zf~m8aAlbVXDo@#qU_(WI3|75<^abeD>-$=qEWeH?S|!BwT#t+^vx$4gfKuo$~>WxVdUDa}9CU z$c+>p;z2biiGYpU8{A7jf3@K}i2||4pL-Gs0iuk3b47e7`3j0vxBwF;qC0{n;=}}u zC)BY~Sv-yMDgfek2_P)&{4T<_l2<5h1**Y7I1}@j(jf(1dDrA}pULHyCg$Fp)z=IJ z5!Vcnd0N0$4k;XRH3KC{=6B+r2JqB8?h0Z;h2iLPF z(Fno$pnV&N0*k^BdxS!(sC^GDz^d?gRAG&O;<+MV$R)c%#$DFDI55zG60lw5AWY8M zC=Sjjbdo&wQjXn9_QHBVR_XH#y9G+3<}OrQ$&~Aq)@5)MM3pvK1vU1RUYYl%XQW@% zDZBQpv?Hp_!@jgz{(_(12^nl;pH8WtIl_g$Ye2aC*lOU#$nvg60-l7vgM#$(003Sa zpi}@fAQ%C80^T14wO?U?k6zF$5-@cS{a1$1>Yj?J#tP>1is_6BQg}s)czl~8GwNN<(c zi>lq5Rd|tVN!@DcBh@m|)pEU6L)8Qn3H{esenk;LZI~We165#dS17f*J>>&5d&8gk z(>03eSXzxp8uYnq%`8t9gaK8cLgmOc&*!ymk5rhl)gnl>Pm?S5H_;chYn_^)rEh`h zMyL$7Qm(aDzO*i=w=Vca-HFXQib#E!ZheSIO~OX?i90n~t<_4c^$?={izrws(LUf5 zjEjQSVwDZ$0jau5gWhNb5-eI*>E{eqbyG=;0Ml#|%o=r8$2S%#)Wj@^C%tGG%4<-J zhV5fGpAAC)47D!~qNuV#<|7+Bqnp92LT_*LjTg=Ro6QW7mOvgCr_wTD0-`XyPAu2`9RR+0}2QTOMIvr>I^g& z2RSHEn&w8YI55LjtP!*z1hh5b)o8^KRQ0YG0%FWlaJR-Fu-OUU_^`K?1AOSa)ru8u zXuET8G z3W`Xf!9MY@A7QlP6#;0>wcGcg8j2nJ+}c&#(5}=oP+G@?amQ^3z?H1h9abkQTIL*c z-KFgMk-qEhFRy!ST_=lndg*ogxOMu)bOw}l28ouzNN8)Rh8{K8?je;hHy9TUF?`p^ z9_jeEF-?YuaAy)s7F088PHQzIpcGym%C?(36G#CZBkT1e{SoP9h!-Pn>55&)s(S9` zgAYa#14)X`Y0&LJgd0$2hpZ@ZQqr=&ZYbJ)T(qxUudlaiZAy`LqLeD)yRnAMLJfd>OOa*pqPXphFU-h=|;TM9`& zZ3GV%|K}zCsh4i@ZfG%$ScNi#n&q{RZc0UNN&vF!M%k^+zFXg4-uk(93uw6|10Wql zOO)Sx*t84gyz~gU-R`1?e$;gRP7(uoqrWYRLBFRiAjSa4$h*G}fHP#tv4J_qBn|fN zJRI584LHWyO{QLz5*t#}AJTA_9@2~*+NBS(K5dyog_=5(-P~Z-vkYzbVe{Bw%kp9C z8+{4CXUO0yJV40=5CeQ+LO>cHAK$KByLRt2*iFy}TN{u#TysG8x_tV9Sztie&JzBkk`fS2e2H4289g+ndRK&;OS7?Xufy>?sr z>Kj|)5BN*l1u8j)s5((h;1T- zlma+p0*7(|mqNh34Dg@>p0$8aGvMC}1a<(yy*9_Gq!WpU!c$yMrMaKU@QBJH$7K7( z(PGKevuCOP)ZF8Vd7SJRU~?+Ci|pk_+@1WoXZKM6$BR+g_K-4SyoP| zs0yoUKHYdZvbhyxt;Mu;pS=z;)y|zem!F?sUS6J5Se05*lU-Ivt86T&YAUV2TG7-7 z&S~rF>Oj6)&E<}|*3QQEu9oXPU`f>4)z{H`v$wam>jtB*f8gf8&|u;YRt+p;Zr>fb zJ92OI7gp{6yXNTs^4}Q*)Ez>L{RY%=OS=35)M14MQ0s1x05S1!~B0_uo6 z#nmrBouG_62&l`vWGL%=BmG*_)1Bh#pMbiHPkMNpo?in2bw^)1lGFYPsC!irxw7zA znU*&IutRqMbzpCm&a3D#_D?{aO;7vI4Egx$v7T!mAJR>Dk;LngZyq-|Ht+OSpQc*9 z?_ZqLH0SE;4xjpvg-<^@9S6zUZFi%4>D@@a;<51?Ju4q`t^CVvcK~(M*ZNMg`<+|- za_Us}cEWwP^LTTH>d%z%{+nBCtatY-58jINoEN(O>CMAix3-}tu47@5@H-z;&YY|g zfJa|N_`gZQn#;{3^En61_^w}AeUmD7dTz!};Z^G$5&s*9V4{&iVRt0nx#p&dq_s>A zx*Zb=OBYc;&47v?V}_;+Yqof%OGv$?PR$dGvUR}vMU*o_?)B@i?j5EMMM3An98m<4;QZG}%QxT40{ z%iXh0#cszKQI>3hRNRn+;`H+Yu3I?+cieQv)N1I?BTp5h>Xp0mMYHiFfIFKt0h3bU z!v=E8C@q_qohWE30gSMD3*bZ{4AGnxNJ{4|_H9e&=ve*qcp) zlaAt(5eWu1et~`qK})yAmluw+`6f#QusvR$R}$WHnmi-{V+%^^K%ZvKnV!I_<+4|( z1Q~ZLC&j80a3oTFU>bXXfS-oj zYDk!pP32}zMeupItiJdj_}#f&o;I^|bzlEe|5xbM4W-ersO`4k#QGmJ<*}smTOr-= ziegkC^C|*gCRrlqTpk_Ri%;Ot2qp-j?UM0E=)?@>FiM0<)|q3cG8t&Q02QHG(O@Rz zDF~?3JIm|BU_m*{Z!+KfaFYXXkKxGoSfVk^2HokH2P@Tx8-gWLc%#@r^-8gi4I=!PX0VZBPwu@% zBG+dIEK-@3!mRYP!c*k&mD{HyK$TOnhNW7SM2~scMF{kk3NTSr%~Ja0LZH_9TYkW}DVbYn7+Ek#~wFoJzz3f0|;=7i6t-1tsK3zAUAN&q$v%YiMs_xR%G zSHj#4#`B9V1er+3>}igV&~Z7t&-;kM9Qen0B^!+PFs(!#!D!Q3wl?b-EHceF}ol!k%+J64kIPQ zB6OaQUOxkIk%LRlwmz2v0d?M94BU_=e1H-@X30r7UPcI#={|kV(*zn6WpO7o^(5io z?RxTbz;y?UI}f;Puk8TpJW7wiKfSHz6RDa&dszvZZhZ)a*6`M+K0*Xj*(K50 z)mp6%1Rd1i>IbTyap?4Vb$Rl05g4Y`tP*E1>~0eNX0 ztiwy&=ao(Wl$f9T76jCdpBV=Mb^0F#4vr(+328b`Cm`Yz#*<68OK=oVuA}I+(R#aY z8zeG%Z+ziE{P?#kF+V<$x%=9aJifJ;{rKDCMep>~_-be0kI#2y^j>_lTkE}R@tN|l z@AcaFTFU*u7OC7fm|00{{h~ivyxiztH`RZO=9)kncu)nS`R{A0w2VA>N(Ixol#)7l zN(BS@pHnLM&=0=v5K7C1L-z=;ss)d#<)6!{fT7#(%c_Ph@%Pie|J8l<`0vOLURlA^ zE@AVJ)c*U{3TF3xN5XZEo-*(}W9S(L9$i7&GkA3UchocZj_-GNcXxLOsm|tpXMbh) zc=AF2{{nFS$J0FbvtWWhe*8Fik_AD{zfQ6-|GSf{ZEynVWYVA1ek>*n#5IG#-9L^7 zLYu+h9+a2|=JmMTi~r?vTO48d8=joulLcavFZ^L9hgCJ6st4mcNK0;ux(cF_yJN4< zw^%19Cxf@#?CfkX#Dj<2($X?8$7h%Cgm^H)gYo_MU6u+}SuW0W7^?uhs*wMeE`M37l63JISJ`CUBA{+Ng`rXR>6U|-K#%=mK zKfmk_Kjzmr%Qg2VJfl1G{uH&!yvXL5`K~@Nnooc)1b1uJFM`qh_?w*K5Kb}1(5-ER zcUq*k%sqAW`hP_8!xay1_W#&g-^bn)E^FtuI}*#2A(qFH2H$nc(#wJ~7tRaNdjOP+f;la4kc>AH1Y&@qu=D z*WyjJ?xn>#u1vP38+os2Mn%k)G&D8nr@^ROAU379E9l*a@qAMY&nm`Ag1f>6ZXT& z`Jz;eEU7m`e+JWZyn^eDoG|Z%5fAYRPu{jB6RGJF2ovZfNv{?rXaTuc8&eT?6~wTF zwjU7RYFYuEKq((d#GI}=l%X_PEfoBP+hxVFt(4kxcVE?UAx9{rQ!5FHB_P=qO<`e# zjLpw-yPqW{+!rOhsYV@_;i@kDC-F^34AiYTshD}On^8U!8^W7-^)P3JTJ+WT3x4E|00>)Jx^w}gpj@#OqHU?G_-J;3e+nKF~X**#tv*pB;affm(Vx9Srw%Y z*Ai@%#(frqcMDb3MKs!SeVstb-WWBrnMmT{U=>qN*dF(IT*x7$lUt(zX|meIF!07c z%;1AorVIz|Kd;_^*p_x^>3(o|1W5vL(_uiL(twgwbbE&L*Q-g_E@3eD6LQ+G`=R7~ zIg)h7W(`@sJ$!y#{P+JV+xMZ5c`EZr^&{7GTVoXOV~E(hxrbKLo_6^z)DYQ$2{1` z?l6Y8F~lsh``F#EiFDJ~`83XTk!wiW(+q7-p8WNs!<=IuRJc|v4qzqc`oL%?2khH;)RyhfyPX5QVBr|m|`9V%A`9rb{=sOe|0dx@70H_Jl~ z1K}JluT2*}cAi`e=h;7=&h?e_(2IZYKAr2-VKfEEb(l$#HWE86>)!i2;+9uvIpuRt^8sr#c_TX>7W3^CUhc{f?8bxt~@;PX&{k(%p%mPE)n7|jDEsgxd6+w1YJ{;ROXsI9Fx zKqXuMnk_4FZ~YC(PBg!gmmvCm2D@KlP}puM(=Ar@Wlr}Ut=EEpHuD!d+QM!*?-x7z zV9)5`9d`8h4}|kO?C6!!m%rH2zoYs0kCJD!@21&NZUG=W`e5&)VvrrJ_hX)PzV}Hz zS9lfgkA=T9b)Rh5jeGpJ64lE+5!qTgXnZJQ zwCv~ChJ!a3YEMLs^%)*571#M_a23j5GP8n_+dwPiraayHxyIn`XW75roDzLw-^RTG z(Tzv)E14pEi7=6{gUf%dy@m+P4RD)dm-*Zi5CY_ZZPwj`KbOlYKi}TpzZp{yOOqvT zK1l2TT6^$EuG<@k5*7ZllNGAUJc%o$LO*Iz;Vx7pI%2*nj?G2<^IGT^t$3_ueDB>D zZYKKt1XP-WhLk`H31}%6^sF=$rJX44k|+}phUum%r0?RK1Gt3}Ru0EY`kz%IVLVu& z`$`b*B#it-JR~xaD3oj*5GUWAsAn3WVeTQfmWW%ALJ<;Nnb1NeOuQ?`i-{;?K*Wm? z`?Zrj)>FvZQE^4KmM*E_3&DVr)c4*vxvp4$Ai+)uBIAEnY#kvko8n4G6i&dzQRt&W zsZ^o#M4>a@E`~vo>FFiunc95T>0vzE%+%2Iu(e`zJ{4iWKo=08c&e`lGc8^_edmRs z<*AhJ^t#B*AaJ$LgsT$+T0X$b4his10#+YF71q*G_%!)5@p26GA`C-dg~}5%vWUn^ z?aYyq?9u7)+Vo8Dg`oKWDuO2~u@eTrg!WU#J?jQK(Gju}Nr$wN%B;{kBWLeN=FFAk z9Qx?xgFd&oo?`%!eWD$ZN<1$>P0Ts2?R(g-HSo)WDCC5h4HLeH2RAZfCia|HxCeW=+I2%cuZVs^ng{l@ z1|9Ao%U+e4O3zd8DRh5csChVFOSq`6B>&{HK08DTNwf6N2*kF*>c17~Q40in46Fk& zoHWN%!my4!*bAS+7bS&TbA^dICCNHrWci}>sB|Cj^P3u2NXxr3P{f@J^K!fpdym&D z(2yoypgK{)K5(I2UMo%qc-Byu5>?vpyfE!TNlRer(;+y!y+L$qQJ^cj1A{Z0HxtC* zQV53ZljzlHg){Rq$O(n$KuoN#V%fLi@>8MX8|8dmrI&Rol8W~0O=Q}3Y98FkN2nKI zjSM)k7wxy7@m{Wmhu%ZAJE*=hQ9R4CD8j;2v9dZ;gR<*@Ivp;SA2`ud`CT~ZkyQnt z>n)vej=jb#6Q8%Y+6?I<;CIQ)!AiD>gel(0%_kQlsk^;>^0Fd`g-CH-{v9_qwv|(y2#S{gevgVT(7@Smr;bIu+@hx;2fS>m}z1FejY0> zY+m$c1C5P0cA>sN1pBYqwF#gBUhkZMG!71q-z@=nx|5Ls>w#a_J0*fVVXuO!s*;AD zqK=lLzV7eMHCPmIXdHy^b4F>qpfw!8dmh&CsEV%XUVTe~z6HU+3fx~Sn;7yEkMSFm zMa{jH&5Ts6P50Vb?sc?PHL_DTb5^%-(XetSIN7SXIZFO23S>w@3iiSK?7YCbK$GMP zuCuir0#pxER9!-K+)n8ojZ*hKtnTZs5qNB05ZS;pMl;-BGa^7MGFUr0L_0q8-*(*A zPEJm4Zf<`T+~5h&A|MVt0si+XH&_~+IRoyvV+?(g4gJ#h2WAlivu%$j7=`2;Q;JMN zFMxNxBd5~cBQs3T(9NQ1&0`zAV{_u;sX9p!x@nQR8Ik(=i3XtNsVsee&H4S8XjVxb z)~Ve#nf=5|G-6Ys(bWsa9T!cy=%#%&fz;g7nI&MuV4F2yN4sm6H%iKX09FmZ)J{)8 zwbP%qxcMKi)BkBU4pt3WSy|v_JRz?VY#YGMcuG-qM(L&eswU9E1dhkS8(~9x*X53$ z-z7swZ~yO-p|^hkEE&K>`S6{c)8PN#Fn|>S;-3`(sF&&{5UCKXly&+4Q7tp## zFBQJ9a7x<4(FZkdbXNzxY%Bd34cT3`88pH+P#ifs?^wdbB)$zByDXQi;7E+{P+JEz*?J8;gSV+9cJwMDJg>FK zT!)ylr`U3u^^oWoqdYuq{r6>}nxWBcg*-I9{c>}8;)L9u!#|dcB-lGTqzPGD!wN-w zxD^;rxa7jH8EL?($EfS`>PtCJ+m04<_KuT}p;Wa@pgwq8a-trMTN-92@m7(ZLA&K> z(#;x-IRL8kgUHv+Awk6PvJ+LtDLZ;8o_hvoYEQ9~Hf8EL=$U(8YnO;y;(}evZ=zJ*RHTwPnVoLvqUW#>h@AmhvQ~%UUeP8?XA9^XY4ITQj{>FzHtLSn(^on_C zCZ3#gs>tOwuiRmSBtEJWUWsZfvxV>M?lL*Wu^<&i{) zz{t?<&41~oBt@3eEngjj?ONYc;=4Cx4=m-r2w9aM`T;T}Rd%~hn#N&%ITT8NB^bX4 zb0|BJw}@`cGc|HYvv=tnCA&uKqou`~a&AU}2m>1+OM?(leB~pfyCtS9(l4=vVda5Y z4hwABlcii5SP{rt-LpQzLp?M6t|cG>bK*y)a?`tE8D~|@rN73rlf}}d_TC$H?p-cy z&8}4{jNEJcA`g!s9%6sPlVatPco-^?DE&xoFtH^pj+elYzcY8)2kBQ+GM#!nw7-))LM&+I&RYXS~pm;|r7so;k^?*F% z=&sned^{{A_M8K+mrIND?j5}noltwkCzH1qMKm=`+nh$nYO(9i4a>{1Fpkm*$jbEq z0jGqtrHgCe)tkWcxXV=EQEEuk>9m0j7GJlh5qGR$EL3Sb}<~ z?%c1JGMob+z^(TT4|X(Ioa3`Sx#^iQK86zsg+ITP?7Jj+y~Y0~k7K3Cv9l^vq`&}L zieQWrS?{otZo_y!-kctZvr#^Ib52)~fyp5cLf9x&8T~=botzOY8!=guQ2(;+G{AF% z6NmC?fEck3;hq%!eY)?Z=h(%F3T_}H;9%d2^VH-#X)mQD*8pD22iO$o&nt6Q15Vhy zw|#<(C*1D3Ij^K9Bl#vj9Xn2Z!`@E2qM@Rxz`;Dt$(WQz;xS3hUOb%J_#}nkAy(1j z7c<;ford>?!!0{{0ik1$qMvC1(DK1|(WX#7b5BfOS-Fn>nVv@$oGT@tG4zP z|B@b&`O&Z*3IVRPJQY3*IC$ATE4Eubp!L^$WLPKfZi$eyZlW)R)3~0+zYa~u{`lni zW#i%f@iP{cyFPo2e!C(J!DRWn+3FomxqB^6#u_Ve$ZW69^dX7Wn`=LomA(YjMM+AKtO=^|t>SJr+mRUi-dKY_R$0q20>mhi4tU<0mh2-P&INRS|4| zpWA=Sl=}3?YW`7W9;;j5KOWrPdEu( zB+OC4;bI&W!O;y%r6uXk!M=Tj`C;Qyll9~p5>4fTl;$i{OOma-lh>z^n&6)T4sQWe z7(RuA6d%}%B&M5LI3{~U23m|HdugX0h(yE#=x74;;w)(21NN|x@hnsb8B%JG@b5+` z(}k5=QB)S{5H&6cK+PORCX>DjL^?0H<>6qfjPa$6rRpg(9vzw(_JzjX5Lv4!dzfC=Sd+QvneaOJX2gxh(Yj|v zf6yDVY#*U00ykk)3-fA%Fc!7wYUmQYHd$f72XosAiy+qYJ6fBOF?mEpKFRt#O2?EG zagbT9nyDziVr3M4$%#^Hvrvst#aQH@_1LUEIavwl*7+QXi!a<;|hT_1AJcJqo zMqPu=7sFOYfagzKjguC?E^#hssHvP@STms#4HJhkFl>52$Bc9qPh0hSMSs4g8ghoz z0eB4&!P$y|i{i?#Mys9}IuYLA-XwWEczs($xro*_)O*d+v&Ha09R`b}PNc~&0|jU( zDiej6fcmeaPBQ4ylvFBERXUKy$CiGiK^RR#>T079t&o)UDv2Y2I0>~o8hY_GMoJMU ze_X*g3e!_7=R{Vh^b*$&W2<~CU0mWumyD7|v89@JDZ_A;(1_Z>wh9g4Ak8frc6#r8 z_t;FHLWj}|bE8RKsUH3|njWrN14nrotuNY3Sh{veua1oji9QmCqCgs(g$0OdGxb1A zRy+p)Wyi*e0#Gz9ZfFIbRv)5voGLE8hgBua3GCTzR9)~9r{&cq1kt;th--a!gFjSe zQL=a1jjy)v=Bt-CKi)N9x;h3UXswi&YTu?*Yu?wq?(6^iW&h$!G=(B8;;SeF^jU$NY-B70BxJMQU~s%*aD8WB#Rhov2l(6v1Y!q-$_KoK z{-bTO2HU1oAno@f|DCz`Ka}PY;BI^u!2o1egZ-1_FQvJpqB7_+2Y*Q`se>|eB_+at z@tG^C?o-;Q|J!7)s;UB-%(b+%L1eYA?mn=f;!->Cd(5)aPN^LbAsB&%b9qf8C0#Qm zLpu;+4R%zZ+nk5!0d`d2ZbjVM@83M<4l3sVfwERLI;dvqsAhE(T(#^pRiNG+tf}n% zH5~%Ao&KRZ*L6Ro;~uqRJ3rxNK#u;ywEjc0CK7f2)Ks>%#-QgMBo2W1YLHz`BAFgK zWO?+c9k_q_S9e7|XzCjS7FS*tWM3<9&}0t6s{fQ&e;npfhjswfXI)}_d>sM<4~2xd zoTRvgN4Wo<#>B*WgX4A(Rj}hQ_f6k%m>q{9n@Y zU*#4kEeEj(zZK=@JTrdF$w4!DWk~72vl4#$$?L;vn!@TXM>Oup$s@0HMz{B!?E>ZG ze@F_+$w6u9$Fs9fdwWKAch0R_`M+zk+N;+uU*GA>eivrH+p^!5@}Z%^yCWCI9+W?vxcKB*&9muC zptStetA^p>+u+Rpe^{jbYMVfa{CQ$x3_Me+7=KYKWeILwV3~8#EbFaI5Fb;yh8VVc zZQ>mv!~+VEG-6hrF{2hI^4yFK$Kn$}nfaf#>CaX?|BuZ4H?q1M0u6rk?=th}*StmJ zR*cPno=B(uiF_HN$W1*(sS~FdRVR<3JgWZsmWLO)x!37!E-xj`Lu2pKTmoS9%>d_)ovpZSUuQ_hnc2zvB|=hZ32&7Y>Nu;beYghZ9~^f* zylx3moHzR^3B1q`dvob?;DeieYhRc{S=-_V`)`a-bvNie${#$~mnZ%vVmG zJ*uW;Tdul)LJqD39-09m2ii5TXwwy!lt@#l2fI{_YIc!j***Y@mt&Fd@@zDBkkvAX zs&l^>2fPC4C%F&x^QB21a}u*9k)|NBI-stxF3{2I7vo@~u*fj$afSD?WS!hSGXh{}^A> zToc$fEktG;?`*|89?8txwY+-%K@s;=1d?}QwgY_s`gKFrGh-v8Y4>Q{$^s}eR}4AS z_AKc0_35xv&32A+3!f{F1&uaB-_ybo{2z4j5A>ZPSPyI>$KIJWJbrfk%gyygr;yI? zt9qY0b#x{^tKTqZja@B7#yoCiJy?0S>yyKzxW+L#vf~M-_syWpysP)>EqvPFG7QK; z&p;^Bg21|`uljdNW$f}i0=?<IVBUA6r(&55_4iKO`Qu3}aZ=wWwV+RCT|t9}P@H z&Xz<=*y(dI$5x)Y_+O?!G&=M7RJ6&8PXzpOvf`qx;~NRyr;afRw~aCHk+ye^Oogod z)e`#S+w0iMZT?j|WX$o-)^ZuD%Gfc6MNZ{=Y-)L0{Xjhmx9aU3UGmz0HFL z_C{;A)gOl;a|QLF%-nFkV&hZm$^Lvs<+UA|`C%?lW`1(d*55KU7q>u}`J3JkH)X~3 zGA%rVc4X%9`JYA)i!Xn9>&Af#%K zRdJp9-8TI!^W@x4)2Bjgh5i>UnL@t zc)Z+|w%hu;%V68|UTSUnu65Aj`EOYak<8pwv^E|ZM7Sd&iQSKlz$OktD0jpx;8-G{f_lm`wHZm zcshf3R4r|vnI{)cPIC7w%TarF?tU1Ete$%!wVZs>Zy0WptpW0D(8|A%_JA zA7tBBoaVXvBGyQ!Whqf=#Dot7CFdIPAW*&)%V+7ZmYb}qj3iCR8 zYMToYP95|&?^K=J5m?1u((u%vpZ+>fsne9&ljX7qmciLdq0Ik~O3Rt`4L zuU%M-sWYv-_oy(3S{h%PX2U-^VSc5c-sM4)Gx!9K9^};U>G361-FsuC9G*&9-zIAV zRb=^{h`K{ZKRJK2p6Xp~ZT9e$b(!)9jAq{oeY251Qk?m?P{nii6K&|eOKel6qff8U z&b9a$rBB^JhF|@3;GM`2i;5jN*eDkgL~NFL5JswLTW(c2AbbDCvtG@F!t23%RPP%q zZhPUV*J3Z9ICI}^`if&Gqk>l^W~Xh^N^Rp*5e|%bHLJVUgSNR6Rx{#0cVw-1`etQB zz25MG-&!B@!Q$zj114Wm*KW)yFGk+e8)W5vxyicuGWz)zaqZ4p|N4XHvGXy8TeEAo zfQ!%KHuOaKga*+2Tn<767)+!fSrfmG89NomRRn+<@{rkTo6^darqk~|_afX*WGjiBhp2w}7}d%%He zSOVp*u}m-xP|6h{zvZiMfFt08X|nm%C}9nG zc&c=SB!AMzu5)ioM9KU1xnD9Y_or#QXFyb^1MMFsRF?k_q z4}!7C_mz(Jx4QYvg@5G8!UvI(#FL?@cH0m9Dv$nXm#OYIqn{QXj_mFVWttzV|(k zniMu{a3aOd!KkRcBr*75`n|=pgWunZZm*9V>|ZW^_5!|JVA1KNj4!H>V%= zueRMfrOnUaGhgrB?#ZIE*$8>@`3W+_?Go4=q+I}$NVV=2Uc~e5rEF1 z^Xa&yWq;l(6gMtZah9hd6gBRZR_!eeTjC^2VsXy|ChXH9TfJfkX_1!FF#zXSE)chE znRW`o32j3ut|Gz%GO}~i)FjfyJh9Lj&WqZ(k_H@x$tfy{J%CEH?apkO&ct@aY0&^9 zI+SM#b%_oIA5Md71U3?^o_t!C1m|V|8DtEU1Xxm`7$&M7Pjy?0&!V$&Yr(RJ0M7(m zfB~GJzy!$w$5Ua-EHZ3BLnIVsavBk8!WGGY?DEupkL4`(RKei6UgK34*2VEGgo(3U z3`JZnRD81=b+{FKO9GI3o54jne=1b`HItKziI^S`lJUyPyoTapa?VQPUXz7GBskxa zB0TUJJoDL5`uQdoLALo!g`Pa63>`Kyx`F8T<>QGODq9@^(A;Lk)l)EjUC_U$;xI*k zx4EAsF@9wRE!ByElOVyJY>gA~P%@;P&elwT@u+fUsp16X)iDH4Rdu`^M2;c>9A*hP zdSfH8>ak&{2_`N?9y^IILg?(vmIb)5+@~%`WaHG|(r|%MJn`~CXrs^)UVM&+TX-Nx zRXr_12glin^KdOz*11sNdg13Xz(>pzsRCqyR33W(ON6|Y!*Wkt@K=Q>;~|x<5M}xW zQ6og!62B8RmM4^VX;~C7My#;XyxIsqRRy?+W$p6f9;#)ggZzTVK8AD1!=mNis(-Rm(KBm&b9e(kb@U;!g!ABRIZN{Bou-grgBX)*`Sla zH7eH}mO~hiJxSr3BXGDCAG@=DWXw@V<`y3Mj1=#&q@Bk{;5j@~a;X1;CpJ=TX zrgBkOa6c?!pGd8PZY@t}jUP+=BNYjy0`^p70Ie2EMw-6>4rOwMwpKfVjDw&mtxY)8 zh=YO$Zc?~9iR^RqTCP@hxdrwB5q3FU4pM7fqHY66bd5RYYVBxdzqk%sFa{b_4|t* znK>ZZ3e{_cgEI4&R&-e_Ti<_U9K^HfVwTZoK+r8C>7j2i+YnOIwmx*bYD{EKi zYgc;NuCfKn%&)2Gfim-Jn%gngw9BsP_FdC|dChR^8d0>vSg*s>t;0N~!?LWyy063L zWry8X2TAn0gWh!~x9dBQgHPop?f)CdL0@O^%gz&9ofOfoFukq_x31GMU6Ey7(S2R9 zFT3Klx~QVy;I2E_tvfZQJH4zsv#&e*Wp~b2H%+uBPp_xIt*0oar=+Z>w6CZ9B`7oR z$<2Zb5ju@1aPX0!I1MFE>~y(zeFfm8|0m-hUKCPKfP3}98z`7GY}ZkM+l$b7n1ppd zzN@~bZ+z>3_y5#&y&+A6arn+{+&1rCD?}n^SwuLpvd`NfttcXB z4UuX$TVfVzFjS^%6HXmXQfi5)_zyuU!J>n>8E&pQ+@{-Yo#F(i(L-Lxku1e&U0rsdBl)E`sCjHhSj?{>fM5Dlj?nCMZ*B+ z1}3z&NA578fD%uc;ASkRhtyF~^RAGDWaX9jqsV4dm>3O0MJ) zwcz*kN-tC59<5w&m35Z7l0JeI7Nb65xC*my(j0~B-63rj(KSiHE+^fl0zZt;4aGxb zvdd`;4%(K7$CgJt-b*I=)M(xrJnXkhlloAb!euF!R3tliLS$LeN?B>j=4iHmrF zK!fdbOS6;HR3lFZRmWKO18y;y1?Qx8~#Idc5{$+*p#R(Qc_AvT25F_R#sd_M)ux4Rph;UN@7YHl4_dL>N+yo26B4F3Wlnx zGFn>l%E~G#Dq7mwIyyQ=W=InYC372POJieITU%{oV`EcOD=RB&8yiPQb$eG$XLoJ4 z2fAMV20kIif#Iehk!ImB7LiU)`Yx^p-ri=uzLvqkw$9GZuC5+lUS1C#_(w!K1_lNO z2Zu#QMn*@+qAa5mZQ@ew6Vn}%GaS><&Y1;nxy9}U<(|dW56bI(s~i35n*Hk^1+{dB zv_A=Z^enuqFY4K=hkcls{@7TzghcoB4DbB>z@p;dvhuLH`iJrH@rj8k>FF7nndrQ{ z{KCTG($cc3s_NIM{`N-+PoAbe@5}7%%dD%bYiw+8YioP_xbx}Lr_Z1F_V@R{evKK5 zefc&XGyJw-WVCp4s%&Pia%rjd{Yw4nTI2e9^YHNS=;+wwTo&g#KIXQa-F4E{`s}bSA6b3JQ~CA-)ENLO@+N7s zn;y*clJX{P{=qH`E@OIRAIdhj_6!DG^<0bW;qQEDhcmov3f>BAl_nQ{ zEgp(D9BW4^Rs04N2f}id8rxow$7+&bV@Es$8YDj^n?2i8gmO|C#4$=C5NdP-eW#yD zc&{W4Al^|m6=Xi;NPs~>1*1skiP%u4<5ZhN1@fpEfEg7~2b?x6!6K`)JmRdYE^-z@ zyR`CpKiZ^1j+@I5L|Mc9lCV~$4W3AtkWtD4vf#`#^0T9D&h zk{T)aBMwpK0==8e1hVcNJM6%ZUcv-Bd_>zp<)RG15t+MK*AjbI6YnsZg4MSv_XAkl zL*Msn-YVx)jc7@W3vw)Dy}QGTpY9G_s9<$>kl}qnQtf|25_gRNUS28mn?Q4~29q1& z+$N4NGS8Ozi@@W1c%{QKeZk1{i{nDNNnQza?L~V@bzPthY;oqe$*%?iyp zLm{7;F7kES#+;Y8oxHRTT??gnPvS$wtvS65=?lWaGnuyES9b3~{w&Oa#^}cmVmrw( zv`K`u$sVytLGkEBV;O}}2x?{g1x?8ZXvkTh)u+q0L6#I8{iByfTh9M4% z4O&8#he+IKK_oCj=ULaM>x~{B(0-Fic!@_-FY$2`faCjtrH*-=>)G+4T*b_ih(kb{ ze=y5IwT_!4HD0~8GF9LJiC`PCAV<)QBLe3pSOB@6a=i0O3!rW>HZzk`<*x{gqc-9rxHouZLWN`;oAXg_I z)Tx(Iy`uvWb1~!l_B0Y}ga&*a#c1N;cUN%>_~0N5Si{o1pVXzPK#EKwY)~e{H2UkSWdXXqC6viX|mQuJug>@ zn)y%NtlWzRF5MQL`!d3XYu$lDi7k4wPDZ6aFPa|owHQ2qwpjb6tqG~yY7{HF)EKwe zY+y=cRHXH;b?r@y#YcCO=M% ztKlm%rS%G>B#+$HwbvGsLMobdA9BkRSyf80K4h`{Al&A{*K+&fFiQef4 zP4>ITFKGo_P6Tii)~&To@l z7+9f@yYanoeDGK&aPphxgQDSeSCRYoryMIA)qlmglKS-FKr9Y(WyS-asn6BjYS~bf zwFo#b5(MQI8A22zl6g6ifMSX=Q!dty8_7nhj)G9dwdYbEIEqEgDaYeuVes?`PUaHh21H4RZq<$8$nk*QoG-eaV1BxR@Bj9`%82s$4 zAJpJ^`Ou z;ZX+hIU6Ju!2#7Dqc%V<79S-up}sAU_XfRanuf%l52}&)DZe293wxMcHuDq4U8x!f zqJ0B`(r>I$Y#|ef-#CB-QXoX4h(r!3E1@b5p~R$g^Bmk>50XMcZpmqt>K$2=HEv_# zwK4H{;Tw2S_`@W6=v=~g#$43+icGvwXZeo@c8OAkDTRZnbxHmJZ*NVxrBk^!Q_FKD@B4Hpt=ekeZZF!9{uux+51A)iMCx#!)cg@xH$09 zlU3qY55`Bndh?VEC3UNR4v46``lJ~1d+tYdvM_Jd9%x?~%GBZ~Ssg3##YcLPg5^RO z{mZ-j7R4OjjfswWAKHEyio#ea2uG?Jfp_*m2Q;d3h@fN12hCjJQGVdU`@RcB zR@A+E9nYnJ=X&J5dZNjGlqvj#=6VM`Fv>AJjxC6xNhEn_BoP%u|7awr6RL=!&<3E~ zHQ*PaQLHzo-U*!^rI;-;h^~fvViOh{*+~my=hac<3-FO0ii`UcD((pybiq^(6h;8V zVI`8A7EnP!`MMJCY+2pIKs#JGv4*i(eY zd*;L|&_NWMlRy~o+t4WbjYQ2}irG=N$T)5OL4^{U=z#;)r$sKe2a~$p(+$-fp{y_g zbO!f4RCO-+{&kGtds|Oh;J2vLOZ*^DAcOZbv|~8=K9`Su9;%Hxh5q$d(VmH;Rh0jrE+O-l)GnFuJ}YQ0=nFO4+GMg-S3M!GxR-=e3U|Q z2Y}O}0liM>mU+5*SUPA0F4d{roga%wz`!!c(X)xi17aMF%iI}Zm8wp|6#+zOF9L@s zj^qq~Ts0KW!Jn2DFzAHhv4W3zGWp42YMsEhcN9L&JU-R%-5^Nsn?QxFFus!PxB%Z$ zwZN@0)7C^33R}=#5Jz&2N}`L{SV;4sB(A(pTR z;;kOe!y3Ay;uF}2UUo&YohwHs)6fBMnPzB57zG|0nuZ5+)JQk#%+YFb^i=0ybdzb3 zOjLP)i)18*DI}9W7L-<4D&SDUNFS_U?JiFT(6YkP+@MTKP_=3beqoqDHd4!@^ih|i z!SDlP3w`9i1C$lTwCrqcY0~;uCu)$koh$6=_o%Gv?4zYH1G@06Uf;`?1d;rhi!XO8D$73l&SpucrEb3-LSZhS9909ya=ZO=8D!M{v3qkr?R)2k8 zV!htadi9BVBbkQxum-b;2AD>JRe!@#LWAAUhPAg1PW%lHR*h~G)y}1jLJ^JLYmI>o zjef0YFHVGyRa1ynMtY)A@368&_pQ*MO~Iv25o;1~VgB>C<*3qTJN{-KoP@qiX;m6S zi^fDVg@pb(TT8KLLq3BcroK+Cw57Vgx{T1!%LQ#j)7or>DvyI?H$j3#S}Er3HFI0L z`CAp{fl@qjDb}hXN?$KTP$xrM0-*}6VcW<==)Fypg0LbK1xQda9~*OdK1FE;02Mq4 zlKahI5#4!D2EVITk~vUanyk!EWto8Xg9%%OQ_$BQTJV1UfTJHc*T>Tj*kMBuH9s0p z4cysdM;1xen@MMsc0hkM-P;6}SO6V0tR0F9Q5X;@HUSR!?y4X_aP8p53cVB{0?Ekq zg0al1ll`diUJhGlT<0O10NIB)9&9UewEe>bUWf&P(!Kcrr>4*b31X*u!tvp$tJRYS z_u0|KDWcmE}G_A z@>7RNk0=KQA1o|lj&s}Una{6!jWab6 zhrmxN5{kq2cKqrWpr*oS?WDLs3cq*+E<;dSG(SH=bsF`j|7tNvY(t^=eSbYodiny! zh8MAc*QebQNZ6w9NG_%bNCKd<26D}1AYGJFDY*G;~3CYd?`8zgdrh!YG5WC6cgi)X81td9L4>!n9|h5%eN1RQ~+kLSNn|ZKf0Y> z`L}o~z7|mg#4x}eHn_zG#V!MrM12~tPT@Y6>Ghr3n$?LkriWMI20B1k|u1I(gD}-AS5@diE<_A~PfdzNIQHg5pc9G#B_iUrY z5FOmP%7rv6Cq&ITLpP#V+)GKfa)btKgpYN+RMG1iyH14Gf6u&|~6=na>n^vox5?3we?ZEh}8 z;Q%CT1j7ZYx0z^+nrJScXdRenU!UmsJ<-WD`9yBA+h($HKyCfh-t%0n`~X5+X#DRpZ`a?3q+czmKQ1c#Swxad_CD1ElZ(>JQ~K(_5uK25 z2gtAXXhvah7!tg)347H@;K{ z-oYWGfkhkYrI6_NVe<3Jf0TE3M#2o>;jCj*Q?nppNNn_qtlvAy&M9sYa0qI6<@OMN z6fiG|iu3bjY|I3)hLM`-HS{HeP#E0vg`k(#;n8c&6>CqJUQ(XTFm#R@QiC`sh6X^n zIyIQ>$UD2%YZVP^ul{_%e6;!YyYb`X2PKC2Th(xR)=5ftFy_yC=tmo3Bup{N3}ikK z_+Z_bW?mWtx51&n_3I#+YRD~vi7nkv6j+cA27d5hf_DxiT@9HL1o0Yts<-((SMmAj zx=mAAf14L?C*ubAuL9!Z$HQe1FSbJ(`5CVXk|G<~IMwl5%g1I8l%+l)gMm*z`pk4P z@mqd_m1T>ag@Qa2oc;L;l)@|kdH>;gB^lbIDH_h}RP zYGO@(=T+jmj`C;4_Yis39tS_aUd0J{4E)@7;vbDssIXgav*$naJR)zC=(G`V?jg8os>2pJfpy!P-4AC%?}yFo7uvmd>0l%Jgcso_Df$5P?j4 z?{|IL^rCts>~U16FwZi#UGEK+b)MkC9N%*I8h8S^h5fWg!ZOXsqPtnj1%wYGmow_;VOF} z+`V&s@^eXCt$5XWo&UL)b2={@amNBA6PRoTI&3r!74wu!1 z-O)@D*O_|D#Xa5fyTSZXtBd>k)ryIvBz=nqhV_~SLas7-2gc2Y4SEu*OJ7XeEuZ;R zXuLZz?{qW{;Idvmw(J&t+u{1b%+spZe|JXyX!*o;;P&Ck?uYlj)6MQn?K{=U+IDZk zaYAnEE2oOh+{>Mc^EDi#EW8Sz#@5N-R^BPSS9*5vY#GRWxLKc;z(#) z85R1XgEaEW$mj?LqSJqDlx2Hmd#)UeKWbE_Q@9m(L{I!7VsdTunXf(Jv-mSIrhe>? zO;CRpQ&hhOws!vwT;8re#$VjVk1A}Q_X+ zC2|-2T<%Cw_HGO(D}3xUT*!(tn4MFmmbhH%t&dx%Bh$lf)R7s4y{jX2)6L2x z{q)OyfKr2m($pb-*HZ&_@2onLG5U|Gg6gn5JhHv7$ZVk@($js4>y1G>GE&}}_u+TZr6^K{>ImQH$5*m%)BPs}lOfeJ zkBGp8!UNNI8F?ECj9)@t*uk%x?>uj~D;^o}N>=LHcaCV_8YRATZE3>Huu-6W3x7q4 z?8PN^)lPb{@wvae)?6u>d^its>4p3^xuC7*!xo+4^aGARbU&zV zrfh~SZhRGK6}Fj9Th+7uPUF)d9rBD8TpGiV}bjQj(TWm;o0_rXY`vReJuX}~*3`HRgmIJl^K9BP!niyd zvM)9ot`}LbSbpHrBvUay6Vgvvf>mjf+t-}+Ukfb0zA2nWj_dpXJg)-2HX_3{=i(Ta z3i01ID$!0Dc*uwsA~Ks*%r)oTtuAWmY#Y@~$LF&m^7C0G8a33lj2ucY@_2Pyw8X|2 z?E5bogr^&HL^Kym*GzJy8yfUNCydR1E}@Ymtp?{BOJ)q0%^LCzMyF#-jWQA$2Gk8E zOO}e_d?Am2V z*voo5<b-c>s&s$2Y}59v(#TJQ8|WJPL3Cd3{6waO(`%~IIv%C&g6%#CN# zvNin5t@@^LDy6+vU2@gkJYC{xJF;fdzwFZa;E}gH4dQ<+SqUT$AOH#=;Rce~+1Yt{ zdBw!UkeAl3hXo>;&TQN!(kUNp3!p8%F$f-%}sC^JHN<}zC zG0(wDqNuP~Oudww|8{j%H9On?T&dX2mHq&#fMn=Dg9t`IN(hAz?A3`C;L6nyLqQXJIW+}y0(LYx9Zg50bE zyzIPue5_o;?0n)J{BnFkB76d}yrQxa{2X#(eB$B~5|YxAGWVn<#pR@Lz+Q%4P?1Sk zh5L>okF=(MjH#HMvb3C`08;;sqO}xKO%ACntE7ETOJ7{gSV7lO#?V#y4x_R#le#3A zik!HKynvy+xR$bv2~yBhL()l4T18b=QB_MtLq}UpNl!~fM^{%v*I3uk)KFK;(oomL z#KhRt(#*ol#?08#!rao*5~=5?Y~-wJ=B{SxrDf`>Y38AA>85S{z|_Xg&^AcN!QaHm z$Krmlv%Zp(p|Z2FuCs-fyQ!*&nTD68nzxmfo0YM@ovxRYd4QvC$bAcE7Z*=A=Leq7 z54;~Zc?Y@q`8)eZxCaD!21NyVyM+3=`T6-q`8!4idBueJ-1G_r28D-)MMQ)IhKB`5 zL_}EKkGJ=WyC0I`8J!y#mFWL4*C)OxA}&23q0m3EG$^G!Iw3DQB_|@iJQ`gYmRbEU zw>I9(GR5B}Am(-_Mw&qvVXH~Zq*R__l zcGeZd*A}HTmLxQkrngpR)R*VBRcF>!SG3jUw$+zDZZ7R?DZiO(wT-Q{&5v3dYulUa zZn_p~+q+sjy4s&~cRi}>>S%r1)%L9C*-aBe@AGH9H|yTsp`oFFP07v8&HuAI;YQ6Z zZ`2%}C=(3T=lu^g@2dT`n)^EsW<$uH9B4eL|CgHcb;aGN`E8~Q&8Ln3spj#7%xi%g zsik6}%X3Ctd#PbB?Q*-C;+x;KSv>XpIPnbp>Tw>rwT+MWc+v&_?o#GUF0oSa?o>#H z_VbR9FC>q0*o+I@`h$d?;TzLFuG}0>p}cK3AYHjVissO+)aiS&J6SB|^=Yc_>Hh3) zgoi&pSz~A9^%n_2bD>I^kxu8yj_-XvUqAE)9(}5?G)PZR~s%FFTaol`>EI0TLV) zl4P83v_MzJ4-6RS%8lkbpd@zX3rAu0;OY^v8P+otsK#O>fh_w_V^ub56AVa%C$;YD zMqS;tmg97vn{oU|ypiPCC5p^6t_p)du z4h%TuY~|3gGz)%pZzblOa#cypG$_fstLBs-fC`2@`&Od#2nme@)u5MLd;MSvspK2B zFX21xHIHcyUu`G$oxaJ15ZQDpTPhJN((ers{Ol_(^XFXNWCwbMlkoANKP)(I(_!Co zpK5?mJUVV~fF19{SOqFB@(B5qt&{`w~oUx!Y$<+J$V`##7Aqh}H zhnFQBCI->Rm*>SX#vyV(4!X;&0~oa?qb6cxS9ZZ!%PmmK)(RDEHzgUR-^kOz+2Roh zFQ2N{-xlZMJ#hyIK%G#URKNcb(3+}@3*vKP*lWW?Rf^U?GQrobEbaS z1N`07j^oUwV@pUBt*JiN6Z3`ccc#p(IC(QSeyCb)n^* zVt-a73AfFK9zo3mOGdX!tkLN89CYfoi)bR*(|Ze zv7n683~4Pqp6mqV-Goz>Xe9b>S2eQOMY!2Fl>)#UV{jQF?-75)!DI+QK|fvM=%f z=fJjFnadXR-7hXK9AwQ_m#wmoHk@4o-*s3?w58Xmn{F#+{|UQnSA}^wm8LECD40H? z2yC-ilvx;Y=Wfxu%wR#P(GQF)iGJFMf0<=cqI!VJ$@-BqvKK*b<~>UOwLHOvXHfqm z=3RRU!QhazL&i)3rZPW#zW~~q#A%eoL@13!Y&kYfv?GF3!iq}8$1Ems3Dp1$02YmtetB0V$TKIj~a`FhsI2E%M2MHeyqvBcS58?P;m`OD4+4VRMRB zOHa(0$YbLfycI20*UX;NrCS{;aohj;^8PgwhcJydsOdA)p~XE8yU`UeP&bwYmP8~` zK&y==pbPc-L z6RRd5>3Xm$XBsAorlI=6|^GMV-0Ls42jB+tu4&m(WtDhfoE7^4_dMhn?fx8+ZFYX11T%l zxS=4wag{|^Fj>YXkpnLX?~MqGF5?>!K5Fp+B`y8WJ=5!k6Pp1k2q#oW3Jn_ z^eB&Jn->EGpic|G0kkO_oX^eQ1_yDM4vT~Qs&C6&gzPab7)bS*J&r*$7N{2Xsn zZ*A27LuUB+=W=@5Wk+^&uEU*QYw9UiJ+m)k{2u@MRG0ky71^s$N}=Cd#_;PA{l5=F zCQA2YaX;p=UtKim|M_B#`?)gv>gxIIpOZ-3uetjQxa(2I~pVPyg zlHR#Qk<*bi3*+a5i1RuLsEZ??&B5#qVh^z}D}Zny2bHr4hak9FP%>Z7S#>(S)1C&L z)6hRdNSadsXPl9ioDlXoZL9;B9tnwav%K7=e+U5bD8Y<5;3ZW&F2@Hzaf-Rb$G;)L zM}t@)q=t*}9p;2IbEK;d3Ws#+5z&w&o8SBj)#Dax82jYWZOBR&}I532;f0yf`4a%Uo{-!M-Ifq1_FhGxm@!zltm8goEcCH#&14EP+ zn)n)zo{iNu3&PJ1fpTqwzG6i|ov=k|s4CRmgaa@~5tPEAeppdFgqTsh%X{}b{M?`& zWi=`eXXS0uV>LX{!1VG#IAtdQpscY}AYjK zOprAQXPP6O-=j+!kzv^8vxMBu6_amM&MRhz`Q^)KVBNm3-}hn9*gqra6OnxxyM*t*yWAjK+exB^eU}kY&rEnp>e0gX4Yd z$yb5&j*v=XNi3LMQVge3cxeO=Y zYH&CdWpyPi;T#Bo4c$Cr`3ib6OH2EjaV0^Qd&Z+yL`@kRJ$F>uNu3Z9AOp*aO;X1^ zYlaeQo?&05Ah1e4DHlqGvoEB|Q8i;nI&iG0D!|vDGjHy$Z)?1Rif+FFoLqHZAsfz(gBbE9nI^|Zr3Kvv2{6fvYo-`h;OGlV|I)|SK z_!r*w#{!B622NFmgnr_(AF+H})xcYdBD7RsX->vz=gm2T%CN*yNT08)iL!Ov4?2kh z0YhY|Kqn?N25Z3g#*G$5aMJ?3*CNvhySwC9i)JIu6UBeusqG@3VBMtq9zlw~0UE{- z3gG$^ywJq8oWVsc^1b!i11<%pE!+wiVgY=f+t47T`vg2m(DxWZLgA`%M?ySd5_CMt z93^}m+2FdLwDv}q!kylV@J?zd7ZQjESi=t?WCng*EC^VVR5ATqLNNo7S~dLh0f|I{zhabRyTKOSYSt)?vTpp|Zk=By*y<;B3!N1?q_f|j?&s9E*N|Eq zMP}{dr_Jf*2wVO>r28feVG%CNo+r$H#$1sYqvvJ)fgov)+&Xttng{~DRm>T%_4tp! zb>B1Vmx{f2{ zC#W95)SeVB?`Jg)IzQ>knjwA;cbC}-n!c~4G0df3+-&BlH-gVYtws5-TSj+ z`>SgD&kw6W7?{K_L!hM+m;>9P0K|rfVO>$!bC@j(7+-LarW|-yCvUf;u6r(Se=R8F zmJOh?wE?S|;ob|c*VmC*_m-W)M|)Wic#aSfburPPU#vB^=~IJ1&%cncb!t@hMfqFP zANSlz=uIf!pc5P|*l*+C2LobL*6s=TQ4$qFajzi6f%(od)K+&5?-rQ;z)Y|!Yomrm ziNi@yYLPu|4||}r4#J0fcmv$*I7xb23|J^hR6Y>Ql2iaUfOy(K_WG(TzI#kr!b}}t zUy=5j`9AsBzM&+d&laIqP_i5(-p+ZZl8pzHxbPHJdWti+7c$U`IDR9%G&*VO`MAfc z`Grl@ZFWI(dh7<^at!SCK>H*W9!z!m+Ay}s${+MO&)1FSWQbNtB!K)NR@J(S8LeOO z>A9>z??M&YqF!a&2t*2uUtJ9Sa?&sQ?UT&JZZAiFvN1jZp59My&5oSll&lIhC_F{W zS8hyHC`}o*DrSUDhH7I5=<=ew75T*LvJC6KvU-QLS3W+ryIS%;#rlu0zvXx`J|i$a z8`ZxwK>tNn0D=Oir`denm@ZYGI^2Uypz#T@nP%U^vlj8PQ23(8KI7dw(@>t2*5-^g zZN>=vj(W9W;>oL>AUQbC4;!7)d`?HHkep3Y0-OO!`zA^Bz)+9KTn;(Wi!b2#Tq3BB zdTxfAfQ7`27EelO)@Mp?a)++X)i{oL(Qc%{wwAPvJCw~pK!s#7D{^T^iD$(%loV#D zWfX2+>x|wP!zEZ09ns(Y)m8icS-ImAo?qr6w(pH(WBmVgx4eJRyz)$9B|+Xi zDSE}HU?nZnEaT&f-Q@~8(^ODywTtKBQPFDY%hmFatEHK%mCS3k@@w_XYq<|reN9)J zA4N31TvK_s)=^>H$^2na{6qK4h}P&28Ll7tA4v$OljZ^hq$?lh$>SW5arT`sUOFB} zBKlEQ{0dpO<=^xU9~&Bo=|i;FOHbnkWD-6K1FXMC$5(ruA^G=u7 zZ0VgelH8<$dUR68aD#1k4fuFOa?_*gG$}mIX*pK~7UHn@aTSnXdM|}YEmgmJBZ{R(kT#Vo$Jxyv3g9pGwK#wQ^k#u^{koJ}O=jIKLGLtHu zFmG93@tOUkvuT}vxBj^&r%2?}XspS$Bq{x~@UnsCvS%S&ENj~mo1ZHU%M}&2FU@vl zepk^GR0G1*E9czonEQHqlm;jCq(9~B5T)WQb7m*??|}v*{x)>c&{sbqT6hd?$F}Xy z21hHO!0owds1oIa-Q1eib_Sq>|9%&4LOSewfeEH~@9S3CAmNLN$Nu%+00NZNY?s

_>Chh3g1ru)i9~q37 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 literal 0 HcmV?d00001 diff --git a/external-deps/python-language-server/resources/hover.gif b/external-deps/python-language-server/resources/hover.gif new file mode 100644 index 0000000000000000000000000000000000000000..cb2bc86dde8713cf01488374f50aa278876f5ff9 GIT binary patch literal 36464 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%0Dv&@F;VKfHe!=EX` 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�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

0jn467e&G*1Tga~r(P0S%TH-p=;zF%&YlS`> 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 O8epBl#KgkIU=09f-c^wR literal 0 HcmV?d00001 diff --git a/external-deps/python-language-server/resources/linting.gif b/external-deps/python-language-server/resources/linting.gif new file mode 100644 index 0000000000000000000000000000000000000000..153f652e708893a21c8cdddf612ac341c4c248c9 GIT binary patch literal 30013 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 PO?AYEW^%L`;Nt%Qy@$Mo literal 0 HcmV?d00001 diff --git a/external-deps/python-language-server/resources/signature-help.gif b/external-deps/python-language-server/resources/signature-help.gif new file mode 100644 index 0000000000000000000000000000000000000000..5e48433890e5b90fb1f60a66e6eb3dc358624d1e GIT binary patch literal 10586 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 literal 0 HcmV?d00001 diff --git a/external-deps/python-language-server/scripts/circle/pypi.sh b/external-deps/python-language-server/scripts/circle/pypi.sh new file mode 100755 index 00000000000..d0eae1be0bb --- /dev/null +++ b/external-deps/python-language-server/scripts/circle/pypi.sh @@ -0,0 +1,17 @@ +#!/bin/bash -e + +if [ -z "$CI" ]; then + echo "Will only continue on CI" + exit +fi + +# build package and upload to private pypi index +rm -f ~/.pypirc +echo "[distutils]" >> ~/.pypirc +echo "index-servers = pypi-private" >> ~/.pypirc +echo "[pypi-private]" >> ~/.pypirc +echo "repository=https://$PYPI_HOST" >> ~/.pypirc +echo "username=$PYPI_USERNAME" >> ~/.pypirc +echo "password=$PYPI_PASSWORD" >> ~/.pypirc + +python setup.py bdist_wheel sdist upload -r pypi-private diff --git a/external-deps/python-language-server/setup.cfg b/external-deps/python-language-server/setup.cfg new file mode 100644 index 00000000000..c2bb1ae8afd --- /dev/null +++ b/external-deps/python-language-server/setup.cfg @@ -0,0 +1,18 @@ +[versioneer] +VCS = git +style = pep440 +versionfile_source = pyls/_version.py +versionfile_build = pyls/_version.py +tag_prefix = +parentdir_prefix = + +[pycodestyle] +ignore = E226, E722, W504 +max-line-length = 120 +exclude = test/plugins/.ropeproject,test/.ropeproject + +[tool:pytest] +testpaths = test +addopts = + --cov-report html --cov-report term --junitxml=pytest.xml + --cov pyls --cov test diff --git a/external-deps/python-language-server/setup.py b/external-deps/python-language-server/setup.py new file mode 100755 index 00000000000..f3c465db93f --- /dev/null +++ b/external-deps/python-language-server/setup.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +from setuptools import find_packages, setup +import versioneer + +README = open('README.rst', 'r').read() + + +setup( + name='python-language-server', + + # Versions should comply with PEP440. For a discussion on single-sourcing + # the version across setup.py and the project code, see + # https://packaging.python.org/en/latest/single_source_version.html + version=versioneer.get_version(), + cmdclass=versioneer.get_cmdclass(), + + description='Python Language Server for the Language Server Protocol', + + long_description=README, + + # The project's main homepage. + url='https://github.com/palantir/python-language-server', + + author='Palantir Technologies, Inc.', + + # You can just specify the packages manually here if your project is + # simple. Or you can use find_packages(). + packages=find_packages(exclude=['contrib', 'docs', 'test', 'test.*']), + + # List run-time dependencies here. These will be installed by pip when + # your project is installed. For an analysis of "install_requires" vs pip's + # requirements files see: + # https://packaging.python.org/en/latest/requirements.html + install_requires=[ + 'configparser; python_version<"3.0"', + 'future>=0.14.0; python_version<"3"', + 'backports.functools_lru_cache; python_version<"3.2"', + 'jedi>=0.17.0,<0.18.0', + 'python-jsonrpc-server>=0.3.2', + 'pluggy', + 'ujson<=1.35; platform_system!="Windows"' + ], + + # List additional groups of dependencies here (e.g. development + # dependencies). You can install these using the following syntax, + # for example: + # $ pip install -e .[test] + extras_require={ + 'all': [ + 'autopep8', + 'flake8>=3.8.0', + 'mccabe>=0.6.0,<0.7.0', + 'pycodestyle>=2.6.0,<2.7.0', + 'pydocstyle>=2.0.0', + 'pyflakes>=2.2.0,<2.3.0', + 'pylint', + 'rope>=0.10.5', + 'yapf', + ], + 'autopep8': ['autopep8'], + 'flake8': ['flake8>=3.8.0'], + 'mccabe': ['mccabe>=0.6.0,<0.7.0'], + 'pycodestyle': ['pycodestyle>=2.6.0,<2.7.0'], + 'pydocstyle': ['pydocstyle>=2.0.0'], + 'pyflakes': ['pyflakes>=2.2.0,<2.3.0'], + 'pylint': ['pylint'], + 'rope': ['rope>0.10.5'], + 'yapf': ['yapf'], + 'test': ['versioneer', 'pylint', 'pytest', 'mock', 'pytest-cov', + 'coverage', 'numpy', 'pandas', 'matplotlib', + 'pyqt5;python_version>="3"'], + }, + + # To provide executable scripts, use entry points in preference to the + # "scripts" keyword. Entry points provide cross-platform support and allow + # pip to create the appropriate form of executable for the target platform. + entry_points={ + 'console_scripts': [ + 'pyls = pyls.__main__:main', + ], + 'pyls': [ + 'autopep8 = pyls.plugins.autopep8_format', + 'folding = pyls.plugins.folding', + 'flake8 = pyls.plugins.flake8_lint', + 'jedi_completion = pyls.plugins.jedi_completion', + 'jedi_definition = pyls.plugins.definition', + 'jedi_hover = pyls.plugins.hover', + 'jedi_highlight = pyls.plugins.highlight', + 'jedi_references = pyls.plugins.references', + 'jedi_rename = pyls.plugins.jedi_rename', + 'jedi_signature_help = pyls.plugins.signature', + 'jedi_symbols = pyls.plugins.symbols', + 'mccabe = pyls.plugins.mccabe_lint', + 'preload = pyls.plugins.preload_imports', + 'pycodestyle = pyls.plugins.pycodestyle_lint', + 'pydocstyle = pyls.plugins.pydocstyle_lint', + 'pyflakes = pyls.plugins.pyflakes_lint', + 'pylint = pyls.plugins.pylint_lint', + 'rope_completion = pyls.plugins.rope_completion', + 'rope_rename = pyls.plugins.rope_rename', + 'yapf = pyls.plugins.yapf_format' + ] + }, +) diff --git a/external-deps/python-language-server/test/__init__.py b/external-deps/python-language-server/test/__init__.py new file mode 100644 index 00000000000..8b18553c0b7 --- /dev/null +++ b/external-deps/python-language-server/test/__init__.py @@ -0,0 +1,11 @@ +# Copyright 2017 Palantir Technologies, Inc. +import sys +import pytest +from pyls 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 --git a/external-deps/python-language-server/test/conftest.py b/external-deps/python-language-server/test/conftest.py new file mode 100644 index 00000000000..59542dd209b --- /dev/null +++ b/external-deps/python-language-server/test/conftest.py @@ -0,0 +1,11 @@ +# Copyright 2017 Palantir Technologies, Inc. +""" py.test configuration""" +import logging +from pyls.__main__ import LOG_FORMAT + +logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT) + + +pytest_plugins = [ + 'test.fixtures' +] diff --git a/external-deps/python-language-server/test/fixtures.py b/external-deps/python-language-server/test/fixtures.py new file mode 100644 index 00000000000..490938a64de --- /dev/null +++ b/external-deps/python-language-server/test/fixtures.py @@ -0,0 +1,73 @@ +# Copyright 2017 Palantir Technologies, Inc. +import os +import sys +from mock import Mock +import pytest + +from pyls import uris +from pyls.config.config import Config +from pyls.python_ls import PythonLanguageServer +from pyls.workspace import Workspace, Document + +if sys.version_info[0] < 3: + from StringIO import StringIO +else: + from io import StringIO + +DOC_URI = uris.from_fs_path(__file__) +DOC = """import sys + +def main(): + print sys.stdin.read() +""" + + +@pytest.fixture +def pyls(tmpdir): + """ Return an initialized python LS """ + ls = PythonLanguageServer(StringIO, StringIO) + + ls.m_initialize( + processId=1, + rootUri=uris.from_fs_path(str(tmpdir)), + initializationOptions={} + ) + + return ls + + +@pytest.fixture +def workspace(tmpdir): + """Return a workspace.""" + return Workspace(uris.from_fs_path(str(tmpdir)), Mock()) + + +@pytest.fixture +def config(workspace): # pylint: disable=redefined-outer-name + """Return a config object.""" + return Config(workspace.root_uri, {}, 0, {}) + + +@pytest.fixture +def doc(workspace): # pylint: disable=redefined-outer-name + return Document(DOC_URI, workspace, DOC) + + +@pytest.fixture +def temp_workspace_factory(workspace): # pylint: disable=redefined-outer-name + ''' + Returns a function that creates a temporary workspace from the files dict. + The dict is in the format {"file_name": "file_contents"} + ''' + def fn(files): + def create_file(name, content): + fn = os.path.join(workspace.root_path, name) + with open(fn, 'w') as f: + f.write(content) + workspace.put_document(uris.from_fs_path(fn), content) + + for name, content in files.items(): + create_file(name, content) + return workspace + + return fn diff --git a/external-deps/python-language-server/test/plugins/__init__.py b/external-deps/python-language-server/test/plugins/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/external-deps/python-language-server/test/plugins/test_autopep8_format.py b/external-deps/python-language-server/test/plugins/test_autopep8_format.py new file mode 100644 index 00000000000..8138952d4e2 --- /dev/null +++ b/external-deps/python-language-server/test/plugins/test_autopep8_format.py @@ -0,0 +1,44 @@ +# Copyright 2017 Palantir Technologies, Inc. +from pyls import uris +from pyls.plugins.autopep8_format import pyls_format_document, pyls_format_range +from pyls.workspace import Document + +DOC_URI = uris.from_fs_path(__file__) +DOC = """a = 123 + + + + +def func(): + pass +""" + +GOOD_DOC = """A = ['hello', 'world']\n""" + + +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, workspace): + doc = Document(DOC_URI, workspace, DOC) + + def_range = { + 'start': {'line': 0, 'character': 0}, + 'end': {'line': 2, 'character': 0} + } + res = pyls_format_range(config, doc, def_range) + + assert len(res) == 1 + + # Make sure the func is still badly formatted + assert res[0]['newText'] == "a = 123\n\n\n\n\ndef func():\n pass\n" + + +def test_no_change(config, workspace): + doc = Document(DOC_URI, workspace, GOOD_DOC) + assert not pyls_format_document(config, doc) diff --git a/external-deps/python-language-server/test/plugins/test_completion.py b/external-deps/python-language-server/test/plugins/test_completion.py new file mode 100644 index 00000000000..2b8847fcfa8 --- /dev/null +++ b/external-deps/python-language-server/test/plugins/test_completion.py @@ -0,0 +1,337 @@ +# Copyright 2017 Palantir Technologies, Inc. +import os +import sys + +from test.test_utils import MockWorkspace +import pytest + +from pyls import uris, lsp +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 + + +PY2 = sys.version[0] == '2' +LINUX = sys.platform.startswith('linux') +CI = os.environ.get('CI') +LOCATION = os.path.realpath( + os.path.join(os.getcwd(), os.path.dirname(__file__)) +) +DOC_URI = uris.from_fs_path(__file__) +DOC = """import os +print os.path.isabs("/tmp") + +def hello(): + pass + +def _a_hello(): + pass + +class Hello(): + + @property + def world(self): + return None + + def everyone(self, a, b, c=None, d=2): + pass + +print Hello().world + +print Hello().every +""" + + +def test_rope_import_completion(config, workspace): + com_position = {'line': 0, 'character': 7} + doc = Document(DOC_URI, workspace, DOC) + items = pyls_rope_completions(config, workspace, doc, com_position) + assert items is None + + +def test_jedi_completion(config, workspace): + # Over 'i' in os.path.isabs(...) + com_position = {'line': 1, 'character': 15} + doc = Document(DOC_URI, workspace, DOC) + items = pyls_jedi_completions(config, doc, com_position) + + assert items + 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}) + + +def test_jedi_completion_with_fuzzy_enabled(config, workspace): + # Over 'i' in os.path.isabs(...) + config.update({'plugins': {'jedi_completion': {'fuzzy': True}}}) + com_position = {'line': 1, 'character': 15} + doc = Document(DOC_URI, workspace, DOC) + + items = pyls_jedi_completions(config, doc, com_position) + + assert items + assert items[0]['label'] == 'commonprefix(list)' + + # Test we don't throw with big character + pyls_jedi_completions(config, doc, {'line': 1, 'character': 1000}) + + +def test_rope_completion(config, workspace): + # Over 'i' in os.path.isabs(...) + com_position = {'line': 1, 'character': 15} + workspace.put_document(DOC_URI, source=DOC) + doc = workspace.get_document(DOC_URI) + items = pyls_rope_completions(config, workspace, doc, com_position) + + assert items + assert items[0]['label'] == 'isabs' + + +def test_jedi_completion_ordering(config, workspace): + # Over the blank line + com_position = {'line': 8, 'character': 0} + doc = Document(DOC_URI, workspace, DOC) + completions = pyls_jedi_completions(config, doc, com_position) + + items = {c['label']: c['sortText'] for c in completions} + + # And that 'hidden' functions come after unhidden ones + assert items['hello()'] < items['_a_hello()'] + + +def test_jedi_property_completion(config, workspace): + # Over the 'w' in 'print Hello().world' + com_position = {'line': 18, 'character': 15} + doc = Document(DOC_URI, workspace, DOC) + completions = pyls_jedi_completions(config, doc, com_position) + + items = {c['label']: c['sortText'] for c in completions} + + # Ensure we can complete the 'world' property + assert 'world' in list(items.keys())[0] + + +def test_jedi_method_completion(config, workspace): + # Over the 'y' in 'print Hello().every' + com_position = {'line': 20, 'character': 19} + doc = Document(DOC_URI, workspace, DOC) + + config.capabilities['textDocument'] = {'completion': {'completionItem': {'snippetSupport': True}}} + config.update({'plugins': {'jedi_completion': {'include_params': True}}}) + + completions = pyls_jedi_completions(config, doc, com_position) + everyone_method = [completion for completion in completions if completion['label'] == 'everyone(a, b, c, d)'][0] + + # Ensure we only generate snippets for positional args + assert everyone_method['insertTextFormat'] == lsp.InsertTextFormat.Snippet + assert everyone_method['insertText'] == 'everyone(${1:a}, ${2:b})$0' + + # Disable param snippets + config.update({'plugins': {'jedi_completion': {'include_params': False}}}) + + completions = pyls_jedi_completions(config, doc, com_position) + everyone_method = [completion for completion in completions if completion['label'] == 'everyone(a, b, c, d)'][0] + + assert 'insertTextFormat' not in everyone_method + assert everyone_method['insertText'] == 'everyone' + + +@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, 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, workspace, doc_pyqt) + completions = pyls_jedi_completions(config, doc, com_position) + + assert completions is not None + + +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, workspace, doc_numpy) + 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, workspace): + doc_pandas = "import pandas as pd; pd." + com_position = {'line': 0, 'character': len(doc_pandas)} + doc = Document(DOC_URI, workspace, doc_pandas) + 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, workspace): + doc_mpl = "import matplotlib.pyplot as plt; plt." + com_position = {'line': 0, 'character': len(doc_mpl)} + doc = Document(DOC_URI, workspace, doc_mpl) + 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, workspace): + doc_snippets = 'from collections import defaultdict \na=defaultdict' + com_position = {'line': 0, 'character': 35} + doc = Document(DOC_URI, workspace, doc_snippets) + config.capabilities['textDocument'] = { + 'completion': {'completionItem': {'snippetSupport': True}}} + config.update({'plugins': {'jedi_completion': {'include_params': True}}}) + completions = pyls_jedi_completions(config, doc, com_position) + assert completions[0]['insertText'] == 'defaultdict' + + com_position = {'line': 1, 'character': len(doc_snippets)} + completions = pyls_jedi_completions(config, doc, com_position) + assert completions[0]['insertText'] == 'defaultdict($0)' + assert completions[0]['insertTextFormat'] == lsp.InsertTextFormat.Snippet + + +def test_completion_with_class_objects(config, workspace): + doc_text = 'class FOOBAR(Object): 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_class_objects': True, + }}}) + completions = pyls_jedi_completions(config, doc, com_position) + assert len(completions) == 2 + + assert completions[0]['label'] == 'FOOBAR' + assert completions[0]['kind'] == lsp.CompletionItemKind.Class + + assert completions[1]['label'] == 'FOOBAR object' + assert completions[1]['kind'] == lsp.CompletionItemKind.TypeParameter + + +def test_snippet_parsing(config, workspace): + doc = 'import numpy as np\nnp.logical_and' + completion_position = {'line': 1, 'character': 14} + doc = Document(DOC_URI, workspace, doc) + config.capabilities['textDocument'] = { + 'completion': {'completionItem': {'snippetSupport': True}}} + config.update({'plugins': {'jedi_completion': {'include_params': True}}}) + completions = pyls_jedi_completions(config, doc, completion_position) + out = 'logical_and(${1:x1}, ${2:x2})$0' + assert completions[0]['insertText'] == out + + +def test_multiline_import_snippets(config, workspace): + document = 'from datetime import(\n date,\n datetime)\na=date' + doc = Document(DOC_URI, workspace, document) + config.capabilities['textDocument'] = { + 'completion': {'completionItem': {'snippetSupport': True}}} + config.update({'plugins': {'jedi_completion': {'include_params': True}}}) + + position = {'line': 1, 'character': 5} + completions = pyls_jedi_completions(config, doc, position) + assert completions[0]['insertText'] == 'date' + + position = {'line': 2, 'character': 9} + completions = pyls_jedi_completions(config, doc, position) + assert completions[0]['insertText'] == 'datetime' + + +def test_multiline_snippets(config, workspace): + document = 'from datetime import\\\n date,\\\n datetime \na=date' + doc = Document(DOC_URI, workspace, document) + config.capabilities['textDocument'] = { + 'completion': {'completionItem': {'snippetSupport': True}}} + config.update({'plugins': {'jedi_completion': {'include_params': True}}}) + + position = {'line': 1, 'character': 5} + completions = pyls_jedi_completions(config, doc, position) + assert completions[0]['insertText'] == 'date' + + position = {'line': 2, 'character': 9} + completions = pyls_jedi_completions(config, doc, position) + assert completions[0]['insertText'] == 'datetime' + + +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, 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, 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' + + +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(): + pass +''' + p = tmpdir.mkdir("extra_path") + extra_paths = [str(p)] + p = p.join("foo.py") + p.write(temp_doc_content) + + # Content of doc to test completion + doc_content = """import foo +foo.s""" + doc = Document(DOC_URI, workspace, doc_content) + + # After 'foo.s' without extra paths + com_position = {'line': 1, 'character': 5} + completions = pyls_jedi_completions(config, doc, com_position) + assert completions is None + + # Update config extra paths + config.update({'plugins': {'jedi': {'extra_paths': extra_paths}}}) + doc.update_config(config) + + # After 'foo.s' with extra paths + com_position = {'line': 1, 'character': 5} + completions = pyls_jedi_completions(config, doc, com_position) + assert completions[0]['label'] == 'spam()' + + +@pytest.mark.skipif(PY2 or not LINUX or not CI, reason="tested on linux and python 3 only") +def test_jedi_completion_environment(config): + # Content of doc to test completion + doc_content = '''import logh +''' + doc = Document(DOC_URI, MockWorkspace(), doc_content) + + # After 'import logh' with default environment + com_position = {'line': 0, 'character': 11} + + assert os.path.isdir('/tmp/pyenv/') + + config.update({'plugins': {'jedi': {'environment': None}}}) + doc.update_config(config) + completions = pyls_jedi_completions(config, doc, com_position) + assert completions is None + + # Update config extra environment + env_path = '/tmp/pyenv/bin/python' + config.update({'plugins': {'jedi': {'environment': env_path}}}) + doc.update_config(config) + + # After 'import logh' with new environment + completions = pyls_jedi_completions(config, doc, com_position) + assert completions[0]['label'] == 'loghub' + assert 'changelog generator' in completions[0]['documentation'].lower() diff --git a/external-deps/python-language-server/test/plugins/test_definitions.py b/external-deps/python-language-server/test/plugins/test_definitions.py new file mode 100644 index 00000000000..660741f6075 --- /dev/null +++ b/external-deps/python-language-server/test/plugins/test_definitions.py @@ -0,0 +1,57 @@ +# Copyright 2017 Palantir Technologies, Inc. +from pyls import uris +from pyls.plugins.definition import pyls_definitions +from pyls.workspace import Document + + +DOC_URI = uris.from_fs_path(__file__) +DOC = """def a(): + pass + +print a() + + +class Directory(object): + def __init__(self): + self.members = dict() + + def add_member(self, id, name): + self.members[id] = name +""" + + +def test_definitions(config, workspace): + # Over 'a' in print a + cursor_pos = {'line': 3, 'character': 6} + + # The definition of 'a' + def_range = { + 'start': {'line': 0, 'character': 4}, + 'end': {'line': 0, 'character': 5} + } + + doc = Document(DOC_URI, workspace, DOC) + assert [{'uri': DOC_URI, 'range': def_range}] == pyls_definitions(config, doc, cursor_pos) + + +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, workspace, DOC) + assert not pyls_definitions(config, doc, cursor_pos) + + +def test_assignment(config, workspace): + # Over 's' in self.members[id] + cursor_pos = {'line': 11, 'character': 19} + + # The assignment of 'self.members' + def_range = { + 'start': {'line': 8, 'character': 13}, + 'end': {'line': 8, 'character': 20} + } + + doc = Document(DOC_URI, workspace, DOC) + assert [{'uri': DOC_URI, 'range': def_range}] == pyls_definitions(config, doc, cursor_pos) diff --git a/external-deps/python-language-server/test/plugins/test_flake8_lint.py b/external-deps/python-language-server/test/plugins/test_flake8_lint.py new file mode 100644 index 00000000000..78f486e87d2 --- /dev/null +++ b/external-deps/python-language-server/test/plugins/test_flake8_lint.py @@ -0,0 +1,68 @@ +# Copyright 2019 Palantir Technologies, Inc. +import tempfile +import os +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 + + +DOC_URI = uris.from_fs_path(__file__) +DOC = """import pyls + +t = "TEST" + +def using_const(): +\ta = 8 + 9 +\treturn t +""" + + +def temp_document(doc_text): + temp_file = tempfile.NamedTemporaryFile(mode='w', delete=False) + name = temp_file.name + temp_file.write(doc_text) + temp_file.close() + doc = Document(uris.from_fs_path(name), MockWorkspace()) + + return name, doc + + +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('', workspace, DOC) + diags = flake8_lint.pyls_lint(config, doc) + assert 'Error' in diags[0]['message'] + + +def test_flake8_lint(config): + try: + name, doc = temp_document(DOC) + diags = flake8_lint.pyls_lint(config, doc) + msg = 'local variable \'a\' is assigned to but never used' + unused_var = [d for d in diags if d['message'] == msg][0] + + assert unused_var['source'] == 'flake8' + assert unused_var['code'] == 'F841' + assert unused_var['range']['start'] == {'line': 5, 'character': 1} + assert unused_var['range']['end'] == {'line': 5, 'character': 11} + assert unused_var['severity'] == lsp.DiagnosticSeverity.Warning + + finally: + os.remove(name) + + +def test_flake8_config_param(config): + with patch('pyls.plugins.flake8_lint.Popen') as popen_mock: + mock_instance = popen_mock.return_value + mock_instance.communicate.return_value = [bytes(), bytes()] + flake8_conf = '/tmp/some.cfg' + config.update({'plugins': {'flake8': {'config': flake8_conf}}}) + _name, doc = temp_document(DOC) + flake8_lint.pyls_lint(config, doc) + call_args = popen_mock.call_args.args[0] + assert 'flake8' in call_args + assert '--config={}'.format(flake8_conf) in call_args diff --git a/external-deps/python-language-server/test/plugins/test_folding.py b/external-deps/python-language-server/test/plugins/test_folding.py new file mode 100644 index 00000000000..05f0cdd8c00 --- /dev/null +++ b/external-deps/python-language-server/test/plugins/test_folding.py @@ -0,0 +1,168 @@ +# Copyright 2019 Palantir Technologies, Inc. + +from textwrap import dedent + +from pyls import uris +from pyls.workspace import Document +from pyls.plugins.folding import pyls_folding_range + + +DOC_URI = uris.from_fs_path(__file__) +DOC = dedent(""" +def func(arg1, arg2, arg3, + arg4, arg5, default=func( + 2, 3, 4 + )): + return (2, 3, + 4, 5) + +@decorator( + param1, + param2 +) +def decorated_func(x, y, z): + if x: + return y + elif y: + return z + elif x + y > z: + return True + else: + return x + +class A(): + def method(self, x1): + def inner(): + return x1 + + if x2: + func(3, 4, 5, 6, + 7) + elif x3 < 2: + pass + else: + more_complex_func(2, 3, 4, 5, 6, + 8) + return inner + +a = 2 +operation = (a_large_variable_that_fills_all_space + + other_embarrasingly_long_variable - 2 * 3 / 5) + +(a, b, c, + d, e, f) = func(3, 4, 5, 6, + 7, 8, 9, 10) + +for i in range(0, 3): + i += 1 + while x < i: + expr = (2, 4) + a = func(expr + i, arg2, arg3, arg4, + arg5, var(2, 3, 4, + 5)) + for j in range(0, i): + if i % 2 == 1: + pass + +compren = [x for x in range(0, 3) + if x == 2] + +with open('doc', 'r') as f: + try: + f / 0 + except: + pass + finally: + raise SomeException() + +def testC(): + pass +""") + +SYNTAX_ERR = dedent(""" +def func(arg1, arg2, arg3, + arg4, arg5, default=func( + 2, 3, 4 + )): + return (2, 3, + 4, 5) + +class A(: + pass + +a = 2 +operation = (a_large_variable_that_fills_all_space + + other_embarrasingly_long_variable - 2 * 3 / + +(a, b, c, + d, e, f) = func(3, 4, 5, 6, + 7, 8, 9, 10 +a = 2 +for i in range(0, 3) + i += 1 + while x < i: + expr = (2, 4) + a = func(expr + i, arg2, arg3, arg4, + arg5, var(2, 3, 4, + 5)) + for j in range(0, i): + if i % 2 == 1: + pass +""") + + +def test_folding(workspace): + doc = Document(DOC_URI, workspace, DOC) + ranges = pyls_folding_range(doc) + expected = [{'startLine': 1, 'endLine': 6}, + {'startLine': 2, 'endLine': 3}, + {'startLine': 5, 'endLine': 6}, + {'startLine': 8, 'endLine': 11}, + {'startLine': 12, 'endLine': 20}, + {'startLine': 13, 'endLine': 14}, + {'startLine': 15, 'endLine': 16}, + {'startLine': 17, 'endLine': 18}, + {'startLine': 19, 'endLine': 20}, + {'startLine': 22, 'endLine': 35}, + {'startLine': 23, 'endLine': 35}, + {'startLine': 24, 'endLine': 25}, + {'startLine': 27, 'endLine': 29}, + {'startLine': 28, 'endLine': 29}, + {'startLine': 30, 'endLine': 31}, + {'startLine': 32, 'endLine': 34}, + {'startLine': 33, 'endLine': 34}, + {'startLine': 38, 'endLine': 39}, + {'startLine': 41, 'endLine': 43}, + {'startLine': 42, 'endLine': 43}, + {'startLine': 45, 'endLine': 54}, + {'startLine': 47, 'endLine': 51}, + {'startLine': 49, 'endLine': 51}, + {'startLine': 50, 'endLine': 51}, + {'startLine': 52, 'endLine': 54}, + {'startLine': 53, 'endLine': 54}, + {'startLine': 56, 'endLine': 57}, + {'startLine': 59, 'endLine': 65}, + {'startLine': 60, 'endLine': 61}, + {'startLine': 62, 'endLine': 63}, + {'startLine': 64, 'endLine': 65}, + {'startLine': 67, 'endLine': 68}] + assert ranges == expected + + +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}, + {'startLine': 5, 'endLine': 6}, + {'startLine': 8, 'endLine': 9}, + {'startLine': 12, 'endLine': 13}, + {'startLine': 15, 'endLine': 17}, + {'startLine': 16, 'endLine': 17}, + {'startLine': 19, 'endLine': 28}, + {'startLine': 21, 'endLine': 25}, + {'startLine': 23, 'endLine': 25}, + {'startLine': 24, 'endLine': 25}, + {'startLine': 26, 'endLine': 28}, + {'startLine': 27, 'endLine': 28}] + assert ranges == expected diff --git a/external-deps/python-language-server/test/plugins/test_highlight.py b/external-deps/python-language-server/test/plugins/test_highlight.py new file mode 100644 index 00000000000..40bf52f2b69 --- /dev/null +++ b/external-deps/python-language-server/test/plugins/test_highlight.py @@ -0,0 +1,56 @@ +# Copyright 2017 Palantir Technologies, Inc. +from pyls import lsp, uris +from pyls.workspace import Document +from pyls.plugins.highlight import pyls_document_highlight + + +DOC_URI = uris.from_fs_path(__file__) +DOC = """a = "hello" +a.startswith("b") +""" + + +def test_highlight(workspace): + # Over 'a' in a.startswith + cursor_pos = {'line': 1, 'character': 0} + + doc = Document(DOC_URI, workspace, DOC) + assert pyls_document_highlight(doc, cursor_pos) == [{ + 'range': { + 'start': {'line': 0, 'character': 0}, + 'end': {'line': 0, 'character': 1}, + }, + # The first usage is Write + 'kind': lsp.DocumentHighlightKind.Write + }, { + 'range': { + 'start': {'line': 1, 'character': 0}, + 'end': {'line': 1, 'character': 1}, + }, + # The second usage is Read + 'kind': lsp.DocumentHighlightKind.Read + }] + + +SYS_DOC = '''import sys +print sys.path +''' + + +def test_sys_highlight(workspace): + cursor_pos = {'line': 0, 'character': 8} + + doc = Document(DOC_URI, workspace, SYS_DOC) + assert pyls_document_highlight(doc, cursor_pos) == [{ + 'range': { + 'start': {'line': 0, 'character': 7}, + 'end': {'line': 0, 'character': 10} + }, + 'kind': lsp.DocumentHighlightKind.Write + }, { + 'range': { + 'start': {'line': 1, 'character': 6}, + 'end': {'line': 1, 'character': 9} + }, + 'kind': lsp.DocumentHighlightKind.Read + }] diff --git a/external-deps/python-language-server/test/plugins/test_hover.py b/external-deps/python-language-server/test/plugins/test_hover.py new file mode 100644 index 00000000000..2302b865b46 --- /dev/null +++ b/external-deps/python-language-server/test/plugins/test_hover.py @@ -0,0 +1,68 @@ +# Copyright 2017 Palantir Technologies, Inc. + +from pyls import uris +from pyls.plugins.hover import pyls_hover +from pyls.workspace import Document + +DOC_URI = uris.from_fs_path(__file__) +DOC = """ + +def main(): + \"\"\"hello world\"\"\" + pass +""" + +NUMPY_DOC = """ + +import numpy as np +np.sin + +""" + + +def test_numpy_hover(workspace): + # Over the blank line + no_hov_position = {'line': 1, 'character': 0} + # Over 'numpy' in import numpy as np + numpy_hov_position_1 = {'line': 2, 'character': 8} + # Over 'np' in import numpy as np + numpy_hov_position_2 = {'line': 2, 'character': 17} + # Over 'np' in np.sin + numpy_hov_position_3 = {'line': 3, 'character': 1} + # Over 'sin' in np.sin + numpy_sin_hov_position = {'line': 3, 'character': 4} + + doc = Document(DOC_URI, workspace, NUMPY_DOC) + + 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_2)['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] + + +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, workspace, DOC) + + contents = [{'language': 'python', 'value': 'main()'}, 'hello world'] + + assert { + 'contents': contents + } == pyls_hover(doc, hov_position) + + assert {'contents': ''} == pyls_hover(doc, no_hov_position) diff --git a/external-deps/python-language-server/test/plugins/test_jedi_rename.py b/external-deps/python-language-server/test/plugins/test_jedi_rename.py new file mode 100644 index 00000000000..1d82d9542ca --- /dev/null +++ b/external-deps/python-language-server/test/plugins/test_jedi_rename.py @@ -0,0 +1,48 @@ +# Copyright 2020 Palantir Technologies, Inc. +import os +import sys + +import pytest +from pyls import uris +from pyls.plugins.jedi_rename import pyls_rename +from pyls.workspace import Document + +LT_PY36 = sys.version_info.major < 3 or (sys.version_info.major == 3 and sys.version_info.minor < 6) + +DOC_NAME = 'test1.py' +DOC = '''class Test1(): + pass + +class Test2(Test1): + pass +''' + + +@pytest.fixture +def tmp_workspace(temp_workspace_factory): + return temp_workspace_factory({DOC_NAME: DOC}) + + +@pytest.mark.skipif(LT_PY36, reason='Jedi refactoring isnt supported on Python 2.x/3.5') +def test_jedi_rename(tmp_workspace, config): # pylint: disable=redefined-outer-name + # rename the `Test1` class + position = {'line': 0, 'character': 6} + DOC_URI = uris.from_fs_path(os.path.join(tmp_workspace.root_path, DOC_NAME)) + doc = Document(DOC_URI, tmp_workspace) + + result = pyls_rename(config, tmp_workspace, doc, position, 'ShouldBeRenamed') + assert len(result.keys()) == 1 + + changes = result.get('documentChanges') + assert len(changes) == 1 + changes = changes[0] + + assert changes.get('edits') == [ + { + 'range': { + 'start': {'line': 0, 'character': 0}, + 'end': {'line': 5, 'character': 0}, + }, + 'newText': 'class ShouldBeRenamed():\n pass\n\nclass Test2(ShouldBeRenamed):\n pass\n', + } + ] diff --git a/external-deps/python-language-server/test/plugins/test_mccabe_lint.py b/external-deps/python-language-server/test/plugins/test_mccabe_lint.py new file mode 100644 index 00000000000..6fa4f0bfe42 --- /dev/null +++ b/external-deps/python-language-server/test/plugins/test_mccabe_lint.py @@ -0,0 +1,37 @@ +# Copyright 2017 Palantir Technologies, Inc. +from pyls import lsp, uris +from pyls.workspace import Document +from pyls.plugins import mccabe_lint + +DOC_URI = uris.from_fs_path(__file__) +DOC = """def hello(): +\tpass +""" + +DOC_SYNTAX_ERR = """def hello() +\tpass""" + + +def test_mccabe(config, workspace): + old_settings = config.settings + try: + config.update({'plugins': {'mccabe': {'threshold': 1}}}) + doc = Document(DOC_URI, workspace, DOC) + diags = mccabe_lint.pyls_lint(config, doc) + + assert all([d['source'] == 'mccabe' for d in diags]) + + # One we're expecting is: + msg = 'Cyclomatic complexity too high: 1 (threshold 1)' + mod_import = [d for d in diags if d['message'] == msg][0] + + assert mod_import['severity'] == lsp.DiagnosticSeverity.Warning + assert mod_import['range']['start'] == {'line': 0, 'character': 0} + assert mod_import['range']['end'] == {'line': 0, 'character': 6} + finally: + config._settings = old_settings + + +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/external-deps/python-language-server/test/plugins/test_pycodestyle_lint.py b/external-deps/python-language-server/test/plugins/test_pycodestyle_lint.py new file mode 100644 index 00000000000..f2769a3d499 --- /dev/null +++ b/external-deps/python-language-server/test/plugins/test_pycodestyle_lint.py @@ -0,0 +1,112 @@ +# Copyright 2017 Palantir Technologies, Inc. +import os +from pyls import lsp, uris +from pyls.config.config import Config +from pyls.workspace import Document +from pyls.plugins import pycodestyle_lint + +DOC_URI = uris.from_fs_path(__file__) +DOC = """import sys + +def hello( ): +\tpass +print("hello" + ,"world" +) + +import json + + +""" + + +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]) + + # One we're expecting is: + msg = 'W191 indentation contains tabs' + mod_import = [d for d in diags if d['message'] == msg][0] + + assert mod_import['code'] == 'W191' + assert mod_import['severity'] == lsp.DiagnosticSeverity.Warning + assert mod_import['range']['start'] == {'line': 3, 'character': 0} + assert mod_import['range']['end'] == {'line': 3, 'character': 6} + + msg = 'W391 blank line at end of file' + mod_import = [d for d in diags if d['message'] == msg][0] + + assert mod_import['code'] == 'W391' + assert mod_import['severity'] == lsp.DiagnosticSeverity.Warning + assert mod_import['range']['start'] == {'line': 10, 'character': 0} + assert mod_import['range']['end'] == {'line': 10, 'character': 1} + + msg = "E201 whitespace after '('" + mod_import = [d for d in diags if d['message'] == msg][0] + + assert mod_import['code'] == 'E201' + assert mod_import['severity'] == lsp.DiagnosticSeverity.Warning + assert mod_import['range']['start'] == {'line': 2, 'character': 10} + assert mod_import['range']['end'] == {'line': 2, 'character': 14} + + msg = "E128 continuation line under-indented for visual indent" + mod_import = [d for d in diags if d['message'] == msg][0] + + assert mod_import['code'] == 'E128' + assert mod_import['severity'] == lsp.DiagnosticSeverity.Warning + assert mod_import['range']['start'] == {'line': 5, 'character': 1} + assert mod_import['range']['end'] == {'line': 5, 'character': 10} + + +def test_pycodestyle_config(workspace): + """ Test that we load config files properly. + + Config files are loaded in the following order: + tox.ini pep8.cfg setup.cfg pycodestyle.cfg + + Each overriding the values in the last. + + These files are first looked for in the current document's + directory and then each parent directory until any one is found + terminating at the workspace root. + + If any section called 'pycodestyle' exists that will be solely used + and any config in a 'pep8' section will be ignored + """ + doc_uri = uris.from_fs_path(os.path.join(workspace.root_path, 'test.py')) + workspace.put_document(doc_uri, DOC) + doc = workspace.get_document(doc_uri) + config = Config(workspace.root_uri, {}, 1234, {}) + + # Make sure we get a warning for 'indentation contains tabs' + diags = pycodestyle_lint.pyls_lint(config, doc) + assert [d for d in diags if d['code'] == 'W191'] + + content = { + 'setup.cfg': ('[pycodestyle]\nignore = W191, E201, E128', True), + 'tox.ini': ('', False) + } + + for conf_file, (content, working) in list(content.items()): + # Now we'll add config file to ignore it + with open(os.path.join(workspace.root_path, conf_file), 'w+') as f: + f.write(content) + config.settings.cache_clear() + + # And make sure we don't get any warnings + diags = pycodestyle_lint.pyls_lint(config, doc) + assert len([d for d in diags if d['code'] == 'W191']) == (0 if working else 1) + assert len([d for d in diags if d['code'] == 'E201']) == (0 if working else 1) + assert [d for d in diags if d['code'] == 'W391'] + + os.unlink(os.path.join(workspace.root_path, conf_file)) + + # Make sure we can ignore via the PYLS config as well + config.update({'plugins': {'pycodestyle': {'ignore': ['W191', 'E201']}}}) + # And make sure we only get one warning + diags = pycodestyle_lint.pyls_lint(config, doc) + assert not [d for d in diags if d['code'] == 'W191'] + assert not [d for d in diags if d['code'] == 'E201'] + assert [d for d in diags if d['code'] == 'W391'] diff --git a/external-deps/python-language-server/test/plugins/test_pydocstyle_lint.py b/external-deps/python-language-server/test/plugins/test_pydocstyle_lint.py new file mode 100644 index 00000000000..9ee7b289dde --- /dev/null +++ b/external-deps/python-language-server/test/plugins/test_pydocstyle_lint.py @@ -0,0 +1,56 @@ +# Copyright 2017 Palantir Technologies, Inc. +import os +from pyls import lsp, uris +from pyls.workspace import Document +from pyls.plugins import pydocstyle_lint + +DOC_URI = uris.from_fs_path(os.path.join(os.path.dirname(__file__), "pydocstyle.py")) +TEST_DOC_URI = uris.from_fs_path(__file__) + +DOC = """import sys + +def hello(): +\tpass + +import json +""" + + +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]) + + # One we're expecting is: + assert diags[0] == { + 'code': 'D100', + 'message': 'D100: Missing docstring in public module', + 'severity': lsp.DiagnosticSeverity.Warning, + 'range': { + 'start': {'line': 0, 'character': 0}, + 'end': {'line': 0, 'character': 11}, + }, + 'source': 'pydocstyle' + } + + +def test_pydocstyle_test_document(config, workspace): + # The default --match argument excludes test_* documents. + doc = Document(TEST_DOC_URI, workspace, "") + diags = pydocstyle_lint.pyls_lint(config, doc) + assert not diags + + +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, 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/external-deps/python-language-server/test/plugins/test_pyflakes_lint.py b/external-deps/python-language-server/test/plugins/test_pyflakes_lint.py new file mode 100644 index 00000000000..aa96826592e --- /dev/null +++ b/external-deps/python-language-server/test/plugins/test_pyflakes_lint.py @@ -0,0 +1,62 @@ +# Copyright 2017 Palantir Technologies, Inc. +from pyls import lsp, uris +from pyls.workspace import Document +from pyls.plugins import pyflakes_lint + +DOC_URI = uris.from_fs_path(__file__) +DOC = """import sys + +def hello(): +\tpass + +import json +""" + +DOC_SYNTAX_ERR = """def hello() + pass +""" + +DOC_UNDEFINED_NAME_ERR = "a = b" + + +DOC_ENCODING = u"""# encoding=utf-8 +import sys +""" + + +def test_pyflakes(workspace): + doc = Document(DOC_URI, workspace, DOC) + diags = pyflakes_lint.pyls_lint(doc) + + # One we're expecting is: + msg = '\'sys\' imported but unused' + 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 + + +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' + assert diag['range']['start'] == {'line': 0, 'character': 12} + assert diag['severity'] == lsp.DiagnosticSeverity.Error + + +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\'' + assert diag['range']['start'] == {'line': 0, 'character': 4} + assert diag['severity'] == lsp.DiagnosticSeverity.Error + + +def test_unicode_encoding(workspace): + doc = Document(DOC_URI, workspace, DOC_ENCODING) + diags = pyflakes_lint.pyls_lint(doc) + + assert len(diags) == 1 + assert diags[0]['message'] == '\'sys\' imported but unused' diff --git a/external-deps/python-language-server/test/plugins/test_pylint_lint.py b/external-deps/python-language-server/test/plugins/test_pylint_lint.py new file mode 100644 index 00000000000..c2bf1bca32a --- /dev/null +++ b/external-deps/python-language-server/test/plugins/test_pylint_lint.py @@ -0,0 +1,118 @@ +# Copyright 2018 Google LLC. +import contextlib +import os +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 + +DOC_URI = uris.from_fs_path(__file__) +DOC = """import sys + +def hello(): +\tpass + +import json +""" + +DOC_SYNTAX_ERR = """def hello() + pass +""" + + +@contextlib.contextmanager +def temp_document(doc_text): + try: + temp_file = tempfile.NamedTemporaryFile(mode='w', delete=False) + name = temp_file.name + temp_file.write(doc_text) + temp_file.close() + yield Document(uris.from_fs_path(name), MockWorkspace()) + finally: + os.remove(name) + + +def write_temp_doc(document, contents): + with open(document.path, 'w') as temp_file: + temp_file.write(contents) + + +def test_pylint(config): + with temp_document(DOC) as doc: + diags = pylint_lint.pyls_lint(config, doc, True) + + msg = '[unused-import] Unused import sys' + 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): + with temp_document(DOC_SYNTAX_ERR) as doc: + diag = pylint_lint.pyls_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': 12} + assert diag['severity'] == lsp.DiagnosticSeverity.Error + + +@py2_only +def test_syntax_error_pylint_py2(config): + with temp_document(DOC_SYNTAX_ERR) as doc: + diag = pylint_lint.pyls_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 + # though, so it works for a test of an empty lint. + assert not pylint_lint.pyls_lint( + config, Document(uris.from_fs_path(__file__), workspace), True) + + +def test_lint_caching(): + # Pylint can only operate on files, not in-memory contents. We cache the + # diagnostics after a run so we can continue displaying them until the file + # is saved again. + # + # We use PylintLinter.lint directly here rather than pyls_lint so we can + # pass --disable=invalid-name to pylint, since we want a temporary file but + # need to ensure that pylint doesn't give us invalid-name when our temp + # file has capital letters in its name. + + flags = '--disable=invalid-name' + with temp_document(DOC) as doc: + # Start with a file with errors. + diags = pylint_lint.PylintLinter.lint(doc, True, flags) + assert diags + + # Fix lint errors and write the changes to disk. Run the linter in the + # in-memory mode to check the cached diagnostic behavior. + write_temp_doc(doc, '') + assert pylint_lint.PylintLinter.lint(doc, False, flags) == diags + + # Now check the on-disk behavior. + assert not pylint_lint.PylintLinter.lint(doc, True, flags) + + # Make sure the cache was properly cleared. + assert not pylint_lint.PylintLinter.lint(doc, False, flags) + + +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__), workspace), False) diff --git a/external-deps/python-language-server/test/plugins/test_references.py b/external-deps/python-language-server/test/plugins/test_references.py new file mode 100644 index 00000000000..a3e5f889ccb --- /dev/null +++ b/external-deps/python-language-server/test/plugins/test_references.py @@ -0,0 +1,80 @@ +# 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 +from pyls._utils import PY2 + + +DOC1_NAME = 'test1.py' +DOC2_NAME = 'test2.py' + +DOC1 = """class Test1(): + pass +""" + +DOC2 = """from test1 import Test1 + +try: + Test1() +except UnicodeError: + pass +""" + + +@pytest.fixture +def tmp_workspace(temp_workspace_factory): + return temp_workspace_factory({ + DOC1_NAME: DOC1, + DOC2_NAME: DOC2, + }) + + +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, tmp_workspace) + + refs = pyls_references(doc1, position) + + # Definition, the import and the instantiation + assert len(refs) == 3 + + # Briefly check excluding the definitions (also excludes imports, only counts uses) + no_def_refs = pyls_references(doc1, position, exclude_declaration=True) + assert len(no_def_refs) == 1 + + # Make sure our definition is correctly located + doc1_ref = [u for u in refs if u['uri'] == DOC1_URI][0] + assert doc1_ref['range']['start'] == {'line': 0, 'character': 6} + assert doc1_ref['range']['end'] == {'line': 0, 'character': 11} + + # Make sure our import is correctly located + doc2_import_ref = [u for u in refs if u['uri'] != DOC1_URI][0] + assert doc2_import_ref['range']['start'] == {'line': 0, 'character': 18} + assert doc2_import_ref['range']['end'] == {'line': 0, 'character': 23} + + doc2_usage_ref = [u for u in refs if u['uri'] != DOC1_URI][1] + assert doc2_usage_ref['range']['start'] == {'line': 3, 'character': 4} + 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} + doc2_uri = uris.from_fs_path(os.path.join(tmp_workspace.root_path, DOC2_NAME)) + doc2 = Document(doc2_uri, tmp_workspace) + + refs = pyls_references(doc2, position) + assert len(refs) >= 1 + + expected = {'start': {'line': 4, 'character': 7}, + 'end': {'line': 4, 'character': 19}} + ranges = [r['range'] for r in refs] + assert expected in ranges diff --git a/external-deps/python-language-server/test/plugins/test_rope_rename.py b/external-deps/python-language-server/test/plugins/test_rope_rename.py new file mode 100644 index 00000000000..45bd6bbd440 --- /dev/null +++ b/external-deps/python-language-server/test/plugins/test_rope_rename.py @@ -0,0 +1,42 @@ +import os + +import pytest +from pyls import uris +from pyls.plugins.rope_rename import pyls_rename +from pyls.workspace import Document + +DOC_NAME = "test1.py" +DOC = """class Test1(): + pass + +class Test2(Test1): + pass +""" + + +@pytest.fixture +def tmp_workspace(temp_workspace_factory): + return temp_workspace_factory({DOC_NAME: DOC}) + + +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, tmp_workspace) + + result = pyls_rename(config, tmp_workspace, doc, position, "ShouldBeRenamed") + assert len(result.keys()) == 1 + + changes = result.get("documentChanges") + assert len(changes) == 1 + changes = changes[0] + + assert changes.get("edits") == [ + { + "range": { + "start": {"line": 0, "character": 0}, + "end": {"line": 5, "character": 0}, + }, + "newText": "class ShouldBeRenamed():\n pass\n\nclass Test2(ShouldBeRenamed):\n pass\n", + } + ] diff --git a/external-deps/python-language-server/test/plugins/test_signature.py b/external-deps/python-language-server/test/plugins/test_signature.py new file mode 100644 index 00000000000..b6b5111a9af --- /dev/null +++ b/external-deps/python-language-server/test/plugins/test_signature.py @@ -0,0 +1,94 @@ +# Copyright 2017 Palantir Technologies, Inc. +import pytest +from pyls import uris +from pyls.plugins import signature +from pyls.workspace import Document + +DOC_URI = uris.from_fs_path(__file__) +DOC = """import sys + +def main(param1, param2): + \"\"\" Main docstring + + Args: + param1 (str): Docs for param1 + \"\"\" + raise Exception() + +main( +""" + +MULTI_LINE_DOC = """import sys + +def main(param1=None, + param2=None, + param3=None, + param4=None, + param5=None, + param6=None, + param7=None, + param8=None): + \"\"\" Main docstring + + Args: + param1 (str): Docs for param1 + \"\"\" + raise Exception() + +main( +""" + + +def test_no_signature(workspace): + # Over blank line + sig_position = {'line': 9, 'character': 0} + doc = Document(DOC_URI, workspace, DOC) + + sigs = signature.pyls_signature_help(doc, sig_position)['signatures'] + assert not sigs + + +def test_signature(workspace): + # Over '( ' in main( + sig_position = {'line': 10, 'character': 5} + doc = Document(DOC_URI, workspace, DOC) + + sig_info = signature.pyls_signature_help(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 sig_info['activeParameter'] == 0 + + +def test_multi_line_signature(workspace): + # Over '( ' in main( + sig_position = {'line': 17, 'character': 5} + doc = Document(DOC_URI, workspace, MULTI_LINE_DOC) + + sig_info = signature.pyls_signature_help(doc, sig_position) + + sigs = sig_info['signatures'] + assert len(sigs) == 1 + assert sigs[0]['label'] == ( + 'main(param1=None, param2=None, param3=None, param4=None, ' + '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 sig_info['activeParameter'] == 0 + + +@pytest.mark.parametrize('regex,doc', [ + (signature.SPHINX, " :param test: parameter docstring"), + (signature.EPYDOC, " @param test: parameter docstring"), + (signature.GOOGLE, " test (str): parameter docstring") +]) +def test_docstring_params(regex, doc): + m = regex.match(doc) + assert m.group('param') == "test" + assert m.group('doc') == "parameter docstring" diff --git a/external-deps/python-language-server/test/plugins/test_symbols.py b/external-deps/python-language-server/test/plugins/test_symbols.py new file mode 100644 index 00000000000..7bfb73ea01f --- /dev/null +++ b/external-deps/python-language-server/test/plugins/test_symbols.py @@ -0,0 +1,91 @@ +# Copyright 2017 Palantir Technologies, Inc. +import os +import sys + +from test.test_utils import MockWorkspace +import pytest + +from pyls import uris +from pyls.plugins.symbols import pyls_document_symbols +from pyls.lsp import SymbolKind +from pyls.workspace import Document + + +PY2 = sys.version[0] == '2' +LINUX = sys.platform.startswith('linux') +CI = os.environ.get('CI') +DOC_URI = uris.from_fs_path(__file__) +DOC = """import sys + +a = 'hello' + +class B: + def __init__(self): + x = 2 + self.y = x + +def main(x): + y = 2 * x + return y + +""" + + +def helper_check_symbols_all_scope(symbols): + # All eight symbols (import sys, a, B, __init__, x, y, main, y) + assert len(symbols) == 8 + + def sym(name): + return [s for s in symbols if s['name'] == name][0] + + # Check we have some sane mappings to VSCode constants + assert sym('a')['kind'] == SymbolKind.Variable + assert sym('B')['kind'] == SymbolKind.Class + assert sym('__init__')['kind'] == SymbolKind.Function + assert sym('main')['kind'] == SymbolKind.Function + + # Not going to get too in-depth here else we're just testing Jedi + assert sym('a')['location']['range']['start'] == {'line': 2, 'character': 0} + + +def test_symbols(config, workspace): + doc = Document(DOC_URI, workspace, DOC) + config.update({'plugins': {'jedi_symbols': {'all_scopes': False}}}) + symbols = pyls_document_symbols(config, doc) + + # All four symbols (import sys, a, B, main) + # y is not in the root scope, it shouldn't be returned + assert len(symbols) == 4 + + def sym(name): + return [s for s in symbols if s['name'] == name][0] + + # Check we have some sane mappings to VSCode constants + assert sym('a')['kind'] == SymbolKind.Variable + assert sym('B')['kind'] == SymbolKind.Class + assert sym('main')['kind'] == SymbolKind.Function + + # Not going to get too in-depth here else we're just testing Jedi + assert sym('a')['location']['range']['start'] == {'line': 2, 'character': 0} + + # Ensure that the symbol range spans the whole definition + assert sym('main')['location']['range']['start'] == {'line': 9, 'character': 0} + assert sym('main')['location']['range']['end'] == {'line': 12, 'character': 0} + + +def test_symbols_all_scopes(config, 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, MockWorkspace(), DOC) + + # Update config extra environment + env_path = '/tmp/pyenv/bin/python' + config.update({'plugins': {'jedi': {'environment': env_path}}}) + doc.update_config(config) + symbols = pyls_document_symbols(config, doc) + helper_check_symbols_all_scope(symbols) diff --git a/external-deps/python-language-server/test/plugins/test_yapf_format.py b/external-deps/python-language-server/test/plugins/test_yapf_format.py new file mode 100644 index 00000000000..e3e198e6048 --- /dev/null +++ b/external-deps/python-language-server/test/plugins/test_yapf_format.py @@ -0,0 +1,58 @@ +# Copyright 2017 Palantir Technologies, Inc. +from pyls import uris +from pyls.plugins.yapf_format import pyls_format_document, pyls_format_range +from pyls.workspace import Document + +DOC_URI = uris.from_fs_path(__file__) +DOC = """A = [ + 'h', 'w', + + 'a' + ] + +B = ['h', + + +'w'] +""" + +GOOD_DOC = """A = ['hello', 'world']\n""" + + +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(workspace): + doc = Document(DOC_URI, workspace, DOC) + + def_range = { + 'start': {'line': 0, 'character': 0}, + 'end': {'line': 4, 'character': 10} + } + res = pyls_format_range(doc, def_range) + + assert len(res) == 1 + + # Make sure B is still badly formatted + assert res[0]['newText'] == "A = ['h', 'w', 'a']\n\nB = ['h',\n\n\n'w']\n" + + +def test_no_change(workspace): + doc = Document(DOC_URI, workspace, GOOD_DOC) + assert not pyls_format_document(doc) + + +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), 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/external-deps/python-language-server/test/test_document.py b/external-deps/python-language-server/test/test_document.py new file mode 100644 index 00000000000..dc54613a84f --- /dev/null +++ b/external-deps/python-language-server/test/test_document.py @@ -0,0 +1,99 @@ +# Copyright 2017 Palantir Technologies, Inc. +from test.fixtures import DOC_URI, DOC +from pyls.workspace import Document + + +def test_document_props(doc): + assert doc.uri == DOC_URI + assert doc.source == DOC + + +def test_document_lines(doc): + assert len(doc.lines) == 4 + assert doc.lines[0] == 'import sys\n' + + +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)) + + +def test_offset_at_position(doc): + assert doc.offset_at_position({'line': 0, 'character': 8}) == 8 + assert doc.offset_at_position({'line': 1, 'character': 5}) == 16 + assert doc.offset_at_position({'line': 2, 'character': 0}) == 12 + assert doc.offset_at_position({'line': 2, 'character': 4}) == 16 + assert doc.offset_at_position({'line': 4, 'character': 0}) == 51 + + +def test_word_at_position(doc): + """ Return the position under the cursor (or last in line if past the end) """ + # import sys + assert doc.word_at_position({'line': 0, 'character': 8}) == 'sys' + # Past end of import sys + assert doc.word_at_position({'line': 0, 'character': 1000}) == 'sys' + # Empty line + assert doc.word_at_position({'line': 1, 'character': 5}) == '' + # def main(): + assert doc.word_at_position({'line': 2, 'character': 0}) == 'def' + # Past end of file + assert doc.word_at_position({'line': 4, 'character': 0}) == '' + + +def test_document_empty_edit(workspace): + doc = Document('file:///uri', workspace, u'') + doc.apply_change({ + 'range': { + 'start': {'line': 0, 'character': 0}, + 'end': {'line': 0, 'character': 0} + }, + 'text': u'f' + }) + assert doc.source == u'f' + + +def test_document_line_edit(workspace): + doc = Document('file:///uri', workspace, u'itshelloworld') + doc.apply_change({ + 'text': u'goodbye', + 'range': { + 'start': {'line': 0, 'character': 3}, + 'end': {'line': 0, 'character': 8} + } + }) + assert doc.source == u'itsgoodbyeworld' + + +def test_document_multiline_edit(workspace): + old = [ + "def hello(a, b):\n", + " print a\n", + " print b\n" + ] + 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} + }}) + assert doc.lines == [ + "def hello(a, b):\n", + " print a, b\n" + ] + + +def test_document_end_of_file_edit(workspace): + old = [ + "print 'a'\n", + "print 'b'\n" + ] + 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} + }}) + assert doc.lines == [ + "print 'a'\n", + "print 'b'\n", + "o", + ] diff --git a/external-deps/python-language-server/test/test_language_server.py b/external-deps/python-language-server/test/test_language_server.py new file mode 100644 index 00000000000..14de6c81703 --- /dev/null +++ b/external-deps/python-language-server/test/test_language_server.py @@ -0,0 +1,103 @@ +# Copyright 2017 Palantir Technologies, Inc. +import os +import time +import multiprocessing +from threading import Thread + +from test import unix_only +from pyls_jsonrpc.exceptions import JsonRpcMethodNotFound +import pytest + +from pyls.python_ls import start_io_lang_server, PythonLanguageServer + +CALL_TIMEOUT = 10 + + +def start_client(client): + client.start() + + +class _ClientServer(object): + """ A class to setup a client/server pair """ + def __init__(self, check_parent_process=False): + # Client to Server pipe + csr, csw = os.pipe() + # Server to client pipe + scr, scw = os.pipe() + + ParallelKind = multiprocessing.Process if os.name != 'nt' else Thread + + self.process = ParallelKind(target=start_io_lang_server, args=( + os.fdopen(csr, 'rb'), os.fdopen(scw, 'wb'), check_parent_process, PythonLanguageServer + )) + self.process.start() + + self.client = PythonLanguageServer(os.fdopen(scr, 'rb'), os.fdopen(csw, 'wb'), start_io_lang_server) + self.client_thread = Thread(target=start_client, args=[self.client]) + self.client_thread.daemon = True + self.client_thread.start() + + +@pytest.fixture +def client_server(): + """ A fixture that sets up a client/server pair and shuts down the server + This client/server pair does not support checking parent process aliveness + """ + client_server_pair = _ClientServer() + + yield client_server_pair.client + + shutdown_response = client_server_pair.client._endpoint.request('shutdown').result(timeout=CALL_TIMEOUT) + assert shutdown_response is None + client_server_pair.client._endpoint.notify('exit') + + +@pytest.fixture +def client_exited_server(): + """ A fixture that sets up a client/server pair that support checking parent process aliveness + and assert the server has already exited + """ + client_server_pair = _ClientServer(True) + + # yield client_server_pair.client + yield client_server_pair + + assert client_server_pair.process.is_alive() is False + + +def test_initialize(client_server): # pylint: disable=redefined-outer-name + response = client_server._endpoint.request('initialize', { + 'rootPath': os.path.dirname(__file__), + 'initializationOptions': {} + }).result(timeout=CALL_TIMEOUT) + assert 'capabilities' in response + + +@unix_only +def test_exit_with_parent_process_died(client_exited_server): # pylint: disable=redefined-outer-name + # language server should have already exited before responding + lsp_server, mock_process = client_exited_server.client, client_exited_server.process + # with pytest.raises(Exception): + lsp_server._endpoint.request('initialize', { + 'processId': mock_process.pid, + 'rootPath': os.path.dirname(__file__), + 'initializationOptions': {} + }).result(timeout=CALL_TIMEOUT) + + mock_process.terminate() + time.sleep(CALL_TIMEOUT) + assert not client_exited_server.client_thread.is_alive() + + +def test_not_exit_without_check_parent_process_flag(client_server): # pylint: disable=redefined-outer-name + response = client_server._endpoint.request('initialize', { + 'processId': 1234, + 'rootPath': os.path.dirname(__file__), + 'initializationOptions': {} + }).result(timeout=CALL_TIMEOUT) + assert 'capabilities' in response + + +def test_missing_message(client_server): # pylint: disable=redefined-outer-name + with pytest.raises(JsonRpcMethodNotFound): + client_server._endpoint.request('unknown_method').result(timeout=CALL_TIMEOUT) diff --git a/external-deps/python-language-server/test/test_uris.py b/external-deps/python-language-server/test/test_uris.py new file mode 100644 index 00000000000..d4e177e663f --- /dev/null +++ b/external-deps/python-language-server/test/test_uris.py @@ -0,0 +1,50 @@ +# Copyright 2017 Palantir Technologies, Inc. +from test import unix_only, windows_only +import pytest +from pyls import uris + + +@unix_only +@pytest.mark.parametrize('uri,path', [ + ('file:///foo/bar#frag', '/foo/bar'), + ('file:/foo/bar#frag', '/foo/bar'), + ('file:/foo/space%20%3Fbar#frag', '/foo/space ?bar'), +]) +def test_to_fs_path(uri, path): + assert uris.to_fs_path(uri) == path + + +@windows_only +@pytest.mark.parametrize('uri,path', [ + ('file:///c:/far/boo', 'c:\\far\\boo'), + ('file:///C:/far/boo', 'c:\\far\\boo'), + ('file:///C:/far/space%20%3Fboo', 'c:\\far\\space ?boo'), +]) +def test_win_to_fs_path(uri, path): + assert uris.to_fs_path(uri) == path + + +@unix_only +@pytest.mark.parametrize('path,uri', [ + ('/foo/bar', 'file:///foo/bar'), + ('/foo/space ?bar', 'file:///foo/space%20%3Fbar'), +]) +def test_from_fs_path(path, uri): + assert uris.from_fs_path(path) == uri + + +@windows_only +@pytest.mark.parametrize('path,uri', [ + ('c:\\far\\boo', 'file:///c:/far/boo'), + ('C:\\far\\space ?boo', 'file:///c:/far/space%20%3Fboo') +]) +def test_win_from_fs_path(path, uri): + assert uris.from_fs_path(path) == uri + + +@pytest.mark.parametrize('uri,kwargs,new_uri', [ + ('file:///foo/bar', {'path': '/baz/boo'}, 'file:///baz/boo'), + ('file:///D:/hello%20world.py', {'path': 'D:/hello universe.py'}, 'file:///d:/hello%20universe.py') +]) +def test_uri_with(uri, kwargs, new_uri): + assert uris.uri_with(uri, **kwargs) == new_uri diff --git a/external-deps/python-language-server/test/test_utils.py b/external-deps/python-language-server/test/test_utils.py new file mode 100644 index 00000000000..e6f6e56ad02 --- /dev/null +++ b/external-deps/python-language-server/test/test_utils.py @@ -0,0 +1,106 @@ +# Copyright 2017 Palantir Technologies, Inc. +import time +import sys + +import mock + +from pyls import _utils + + +class MockWorkspace(object): + """Mock workspace used by tests that use jedi environment.""" + + def __init__(self): + """Mock workspace used by tests that use jedi environment.""" + self._environments = {} + + # 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 + obj = mock.Mock() + + @_utils.debounce(0.1) + def call_m(): + obj() + + assert not obj.mock_calls + + call_m() + call_m() + call_m() + assert not obj.mock_calls + + time.sleep(interval * 2) + assert len(obj.mock_calls) == 1 + + call_m() + time.sleep(interval * 2) + assert len(obj.mock_calls) == 2 + + +def test_debounce_keyed_by(): + interval = 0.1 + obj = mock.Mock() + + @_utils.debounce(0.1, keyed_by='key') + def call_m(key): + obj(key) + + assert not obj.mock_calls + + call_m(1) + call_m(2) + call_m(3) + assert not obj.mock_calls + + time.sleep(interval * 2) + obj.assert_has_calls([ + mock.call(1), + mock.call(2), + mock.call(3), + ], any_order=True) + assert len(obj.mock_calls) == 3 + + call_m(1) + call_m(1) + call_m(1) + time.sleep(interval * 2) + assert len(obj.mock_calls) == 4 + + +def test_list_to_string(): + assert _utils.list_to_string("string") == "string" + assert _utils.list_to_string(["a", "r", "r", "a", "y"]) == "a,r,r,a,y" + + +def test_find_parents(tmpdir): + subsubdir = tmpdir.ensure_dir("subdir", "subsubdir") + path = subsubdir.ensure("path.py") + test_cfg = tmpdir.ensure("test.cfg") + + assert _utils.find_parents(tmpdir.strpath, path.strpath, ["test.cfg"]) == [test_cfg.strpath] + + +def test_merge_dicts(): + assert _utils.merge_dicts( + {'a': True, 'b': {'x': 123, 'y': {'hello': 'world'}}}, + {'a': False, 'b': {'y': [], 'z': 987}} + ) == {'a': False, 'b': {'x': 123, 'y': [], 'z': 987}} + + +def test_clip_column(): + assert _utils.clip_column(0, [], 0) == 0 + assert _utils.clip_column(2, ['123'], 0) == 2 + assert _utils.clip_column(3, ['123'], 0) == 3 + assert _utils.clip_column(5, ['123'], 0) == 3 + assert _utils.clip_column(0, ['\n', '123'], 0) == 0 + assert _utils.clip_column(1, ['\n', '123'], 0) == 0 + assert _utils.clip_column(2, ['123\n', '123'], 0) == 2 + assert _utils.clip_column(3, ['123\n', '123'], 0) == 3 + assert _utils.clip_column(4, ['123\n', '123'], 1) == 3 diff --git a/external-deps/python-language-server/test/test_workspace.py b/external-deps/python-language-server/test/test_workspace.py new file mode 100644 index 00000000000..6ecdfbf5956 --- /dev/null +++ b/external-deps/python-language-server/test/test_workspace.py @@ -0,0 +1,199 @@ +# Copyright 2017 Palantir Technologies, Inc. +import os +import sys + +import pytest + +from pyls import uris + +PY2 = sys.version_info.major == 2 + +if PY2: + import pathlib2 as pathlib +else: + import pathlib + + +DOC_URI = uris.from_fs_path(__file__) + + +def path_as_uri(path): + return pathlib.Path(os.path.abspath(path)).as_uri() + + +def test_local(pyls): + """ Since the workspace points to the test directory """ + assert pyls.workspace.is_local() + + +def test_put_document(pyls): + pyls.workspace.put_document(DOC_URI, 'content') + assert DOC_URI in pyls.workspace._docs + + +def test_get_document(pyls): + pyls.workspace.put_document(DOC_URI, 'TEXT') + assert pyls.workspace.get_document(DOC_URI).source == 'TEXT' + + +def test_get_missing_document(tmpdir, pyls): + source = 'TEXT' + doc_path = tmpdir.join("test_document.py") + doc_path.write(source) + doc_uri = uris.from_fs_path(str(doc_path)) + assert pyls.workspace.get_document(doc_uri).source == 'TEXT' + + +def test_rm_document(pyls): + pyls.workspace.put_document(DOC_URI, 'TEXT') + assert pyls.workspace.get_document(DOC_URI).source == 'TEXT' + pyls.workspace.rm_document(DOC_URI) + assert pyls.workspace.get_document(DOC_URI)._source is None + + +@pytest.mark.parametrize('metafiles', [('setup.py',), ('pyproject.toml',), ('setup.py', 'pyproject.toml')]) +def test_non_root_project(pyls, metafiles): + repo_root = os.path.join(pyls.workspace.root_path, 'repo-root') + os.mkdir(repo_root) + project_root = os.path.join(repo_root, 'project-root') + os.mkdir(project_root) + + for metafile in metafiles: + with open(os.path.join(project_root, metafile), 'w+') as f: + f.write('# ' + metafile) + + test_uri = uris.from_fs_path(os.path.join(project_root, 'hello/test.py')) + pyls.workspace.put_document(test_uri, 'assert True') + test_doc = pyls.workspace.get_document(test_uri) + assert project_root in test_doc.sys_path() + + +def test_root_project_with_no_setup_py(pyls): + """Default to workspace root.""" + workspace_root = pyls.workspace.root_path + test_uri = uris.from_fs_path(os.path.join(workspace_root, 'hello/test.py')) + pyls.workspace.put_document(test_uri, 'assert True') + test_doc = pyls.workspace.get_document(test_uri) + assert workspace_root in test_doc.sys_path() + + +def test_multiple_workspaces(tmpdir, pyls): + workspace1_dir = tmpdir.mkdir('workspace1') + workspace2_dir = tmpdir.mkdir('workspace2') + file1 = workspace1_dir.join('file1.py') + file2 = workspace2_dir.join('file1.py') + file1.write('import os') + file2.write('import sys') + + msg = { + 'uri': path_as_uri(str(file1)), + 'version': 1, + 'text': 'import os' + } + + pyls.m_text_document__did_open(textDocument=msg) + assert msg['uri'] in pyls.workspace._docs + + added_workspaces = [{'uri': path_as_uri(str(x))} + for x in (workspace1_dir, workspace2_dir)] + event = {'added': added_workspaces, 'removed': []} + pyls.m_workspace__did_change_workspace_folders(event) + + for workspace in added_workspaces: + assert workspace['uri'] in pyls.workspaces + + workspace1_uri = added_workspaces[0]['uri'] + assert msg['uri'] not in pyls.workspace._docs + assert msg['uri'] in pyls.workspaces[workspace1_uri]._docs + + msg = { + 'uri': path_as_uri(str(file2)), + 'version': 1, + 'text': 'import sys' + } + pyls.m_text_document__did_open(textDocument=msg) + + workspace2_uri = added_workspaces[1]['uri'] + assert msg['uri'] in pyls.workspaces[workspace2_uri]._docs + + event = {'added': [], 'removed': [added_workspaces[0]]} + pyls.m_workspace__did_change_workspace_folders(event) + assert workspace1_uri not in pyls.workspaces + + +def test_multiple_workspaces_wrong_removed_uri(pyls): + workspace = {'uri': 'Test123'} + event = {'added': [], 'removed': [workspace]} + pyls.m_workspace__did_change_workspace_folders(event) + assert workspace['uri'] not in pyls.workspaces + + +def test_root_workspace_changed(pyls): + test_uri = 'Test123' + pyls.root_uri = test_uri + pyls.workspace._root_uri = test_uri + + workspace1 = {'uri': test_uri} + workspace2 = {'uri': 'NewTest456'} + + event = {'added': [workspace2], 'removed': [workspace1]} + pyls.m_workspace__did_change_workspace_folders(event) + + assert workspace2['uri'] == pyls.workspace._root_uri + assert workspace2['uri'] == pyls.root_uri + + +def test_root_workspace_not_changed(pyls): + # removed uri != root_uri + test_uri_1 = 'Test12' + pyls.root_uri = test_uri_1 + pyls.workspace._root_uri = test_uri_1 + workspace1 = {'uri': 'Test1234'} + workspace2 = {'uri': 'NewTest456'} + event = {'added': [workspace2], 'removed': [workspace1]} + pyls.m_workspace__did_change_workspace_folders(event) + assert test_uri_1 == pyls.workspace._root_uri + assert test_uri_1 == pyls.root_uri + # empty 'added' list + test_uri_2 = 'Test123' + new_root_uri = workspace2['uri'] + pyls.root_uri = test_uri_2 + pyls.workspace._root_uri = test_uri_2 + workspace1 = {'uri': test_uri_2} + event = {'added': [], 'removed': [workspace1]} + pyls.m_workspace__did_change_workspace_folders(event) + assert new_root_uri == pyls.workspace._root_uri + assert new_root_uri == pyls.root_uri + # empty 'removed' list + event = {'added': [workspace1], 'removed': []} + pyls.m_workspace__did_change_workspace_folders(event) + assert new_root_uri == pyls.workspace._root_uri + assert new_root_uri == pyls.root_uri + # 'added' list has no 'uri' + workspace2 = {'TESTuri': 'Test1234'} + event = {'added': [workspace2], 'removed': [workspace1]} + pyls.m_workspace__did_change_workspace_folders(event) + assert new_root_uri == pyls.workspace._root_uri + assert new_root_uri == pyls.root_uri + + +def test_root_workspace_removed(tmpdir, pyls): + workspace1_dir = tmpdir.mkdir('workspace1') + workspace2_dir = tmpdir.mkdir('workspace2') + root_uri = pyls.root_uri + + # Add workspaces to the pyls + added_workspaces = [{'uri': path_as_uri(str(x))} + for x in (workspace1_dir, workspace2_dir)] + event = {'added': added_workspaces, 'removed': []} + pyls.m_workspace__did_change_workspace_folders(event) + + # Remove the root workspace + removed_workspaces = [{'uri': root_uri}] + event = {'added': [], 'removed': removed_workspaces} + pyls.m_workspace__did_change_workspace_folders(event) + + # Assert that the first of the workspaces (in alphabetical order) is now + # the root workspace + assert pyls.root_uri == path_as_uri(str(workspace1_dir)) + assert pyls.workspace._root_uri == path_as_uri(str(workspace1_dir)) diff --git a/external-deps/python-language-server/versioneer.py b/external-deps/python-language-server/versioneer.py new file mode 100644 index 00000000000..64fea1c8927 --- /dev/null +++ b/external-deps/python-language-server/versioneer.py @@ -0,0 +1,1822 @@ + +# Version: 0.18 + +"""The Versioneer - like a rocketeer, but for versions. + +The Versioneer +============== + +* like a rocketeer, but for versions! +* https://github.com/warner/python-versioneer +* Brian Warner +* License: Public Domain +* Compatible With: python2.6, 2.7, 3.2, 3.3, 3.4, 3.5, 3.6, and pypy +* [![Latest Version] +(https://pypip.in/version/versioneer/badge.svg?style=flat) +](https://pypi.python.org/pypi/versioneer/) +* [![Build Status] +(https://travis-ci.org/warner/python-versioneer.png?branch=master) +](https://travis-ci.org/warner/python-versioneer) + +This is a tool for managing a recorded version number in distutils-based +python projects. The goal is to remove the tedious and error-prone "update +the embedded version string" step from your release process. Making a new +release should be as easy as recording a new tag in your version-control +system, and maybe making new tarballs. + + +## Quick Install + +* `pip install versioneer` to somewhere to your $PATH +* add a `[versioneer]` section to your setup.cfg (see below) +* run `versioneer install` in your source tree, commit the results + +## Version Identifiers + +Source trees come from a variety of places: + +* a version-control system checkout (mostly used by developers) +* a nightly tarball, produced by build automation +* a snapshot tarball, produced by a web-based VCS browser, like github's + "tarball from tag" feature +* a release tarball, produced by "setup.py sdist", distributed through PyPI + +Within each source tree, the version identifier (either a string or a number, +this tool is format-agnostic) can come from a variety of places: + +* ask the VCS tool itself, e.g. "git describe" (for checkouts), which knows + about recent "tags" and an absolute revision-id +* the name of the directory into which the tarball was unpacked +* an expanded VCS keyword ($Id$, etc) +* a `_version.py` created by some earlier build step + +For released software, the version identifier is closely related to a VCS +tag. Some projects use tag names that include more than just the version +string (e.g. "myproject-1.2" instead of just "1.2"), in which case the tool +needs to strip the tag prefix to extract the version identifier. For +unreleased software (between tags), the version identifier should provide +enough information to help developers recreate the same tree, while also +giving them an idea of roughly how old the tree is (after version 1.2, before +version 1.3). Many VCS systems can report a description that captures this, +for example `git describe --tags --dirty --always` reports things like +"0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the +0.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has +uncommitted changes. + +The version identifier is used for multiple purposes: + +* to allow the module to self-identify its version: `myproject.__version__` +* to choose a name and prefix for a 'setup.py sdist' tarball + +## Theory of Operation + +Versioneer works by adding a special `_version.py` file into your source +tree, where your `__init__.py` can import it. This `_version.py` knows how to +dynamically ask the VCS tool for version information at import time. + +`_version.py` also contains `$Revision$` markers, and the installation +process marks `_version.py` to have this marker rewritten with a tag name +during the `git archive` command. As a result, generated tarballs will +contain enough information to get the proper version. + +To allow `setup.py` to compute a version too, a `versioneer.py` is added to +the top level of your source tree, next to `setup.py` and the `setup.cfg` +that configures it. This overrides several distutils/setuptools commands to +compute the version when invoked, and changes `setup.py build` and `setup.py +sdist` to replace `_version.py` with a small static file that contains just +the generated version data. + +## Installation + +See [INSTALL.md](./INSTALL.md) for detailed installation instructions. + +## Version-String Flavors + +Code which uses Versioneer can learn about its version string at runtime by +importing `_version` from your main `__init__.py` file and running the +`get_versions()` function. From the "outside" (e.g. in `setup.py`), you can +import the top-level `versioneer.py` and run `get_versions()`. + +Both functions return a dictionary with different flavors of version +information: + +* `['version']`: A condensed version string, rendered using the selected + style. This is the most commonly used value for the project's version + string. The default "pep440" style yields strings like `0.11`, + `0.11+2.g1076c97`, or `0.11+2.g1076c97.dirty`. See the "Styles" section + below for alternative styles. + +* `['full-revisionid']`: detailed revision identifier. For Git, this is the + full SHA1 commit id, e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac". + +* `['date']`: Date and time of the latest `HEAD` commit. For Git, it is the + commit date in ISO 8601 format. This will be None if the date is not + available. + +* `['dirty']`: a boolean, True if the tree has uncommitted changes. Note that + this is only accurate if run in a VCS checkout, otherwise it is likely to + be False or None + +* `['error']`: if the version string could not be computed, this will be set + to a string describing the problem, otherwise it will be None. It may be + useful to throw an exception in setup.py if this is set, to avoid e.g. + creating tarballs with a version string of "unknown". + +Some variants are more useful than others. Including `full-revisionid` in a +bug report should allow developers to reconstruct the exact code being tested +(or indicate the presence of local changes that should be shared with the +developers). `version` is suitable for display in an "about" box or a CLI +`--version` output: it can be easily compared against release notes and lists +of bugs fixed in various releases. + +The installer adds the following text to your `__init__.py` to place a basic +version in `YOURPROJECT.__version__`: + + from ._version import get_versions + __version__ = get_versions()['version'] + del get_versions + +## Styles + +The setup.cfg `style=` configuration controls how the VCS information is +rendered into a version string. + +The default style, "pep440", produces a PEP440-compliant string, equal to the +un-prefixed tag name for actual releases, and containing an additional "local +version" section with more detail for in-between builds. For Git, this is +TAG[+DISTANCE.gHEX[.dirty]] , using information from `git describe --tags +--dirty --always`. For example "0.11+2.g1076c97.dirty" indicates that the +tree is like the "1076c97" commit but has uncommitted changes (".dirty"), and +that this commit is two revisions ("+2") beyond the "0.11" tag. For released +software (exactly equal to a known tag), the identifier will only contain the +stripped tag, e.g. "0.11". + +Other styles are available. See [details.md](details.md) in the Versioneer +source tree for descriptions. + +## Debugging + +Versioneer tries to avoid fatal errors: if something goes wrong, it will tend +to return a version of "0+unknown". To investigate the problem, run `setup.py +version`, which will run the version-lookup code in a verbose mode, and will +display the full contents of `get_versions()` (including the `error` string, +which may help identify what went wrong). + +## Known Limitations + +Some situations are known to cause problems for Versioneer. This details the +most significant ones. More can be found on Github +[issues page](https://github.com/warner/python-versioneer/issues). + +### Subprojects + +Versioneer has limited support for source trees in which `setup.py` is not in +the root directory (e.g. `setup.py` and `.git/` are *not* siblings). The are +two common reasons why `setup.py` might not be in the root: + +* Source trees which contain multiple subprojects, such as + [Buildbot](https://github.com/buildbot/buildbot), which contains both + "master" and "slave" subprojects, each with their own `setup.py`, + `setup.cfg`, and `tox.ini`. Projects like these produce multiple PyPI + distributions (and upload multiple independently-installable tarballs). +* Source trees whose main purpose is to contain a C library, but which also + provide bindings to Python (and perhaps other langauges) in subdirectories. + +Versioneer will look for `.git` in parent directories, and most operations +should get the right version string. However `pip` and `setuptools` have bugs +and implementation details which frequently cause `pip install .` from a +subproject directory to fail to find a correct version string (so it usually +defaults to `0+unknown`). + +`pip install --editable .` should work correctly. `setup.py install` might +work too. + +Pip-8.1.1 is known to have this problem, but hopefully it will get fixed in +some later version. + +[Bug #38](https://github.com/warner/python-versioneer/issues/38) is tracking +this issue. The discussion in +[PR #61](https://github.com/warner/python-versioneer/pull/61) describes the +issue from the Versioneer side in more detail. +[pip PR#3176](https://github.com/pypa/pip/pull/3176) and +[pip PR#3615](https://github.com/pypa/pip/pull/3615) contain work to improve +pip to let Versioneer work correctly. + +Versioneer-0.16 and earlier only looked for a `.git` directory next to the +`setup.cfg`, so subprojects were completely unsupported with those releases. + +### Editable installs with setuptools <= 18.5 + +`setup.py develop` and `pip install --editable .` allow you to install a +project into a virtualenv once, then continue editing the source code (and +test) without re-installing after every change. + +"Entry-point scripts" (`setup(entry_points={"console_scripts": ..})`) are a +convenient way to specify executable scripts that should be installed along +with the python package. + +These both work as expected when using modern setuptools. When using +setuptools-18.5 or earlier, however, certain operations will cause +`pkg_resources.DistributionNotFound` errors when running the entrypoint +script, which must be resolved by re-installing the package. This happens +when the install happens with one version, then the egg_info data is +regenerated while a different version is checked out. Many setup.py commands +cause egg_info to be rebuilt (including `sdist`, `wheel`, and installing into +a different virtualenv), so this can be surprising. + +[Bug #83](https://github.com/warner/python-versioneer/issues/83) describes +this one, but upgrading to a newer version of setuptools should probably +resolve it. + +### Unicode version strings + +While Versioneer works (and is continually tested) with both Python 2 and +Python 3, it is not entirely consistent with bytes-vs-unicode distinctions. +Newer releases probably generate unicode version strings on py2. It's not +clear that this is wrong, but it may be surprising for applications when then +write these strings to a network connection or include them in bytes-oriented +APIs like cryptographic checksums. + +[Bug #71](https://github.com/warner/python-versioneer/issues/71) investigates +this question. + + +## Updating Versioneer + +To upgrade your project to a new release of Versioneer, do the following: + +* install the new Versioneer (`pip install -U versioneer` or equivalent) +* edit `setup.cfg`, if necessary, to include any new configuration settings + indicated by the release notes. See [UPGRADING](./UPGRADING.md) for details. +* re-run `versioneer install` in your source tree, to replace + `SRC/_version.py` +* commit any changed files + +## Future Directions + +This tool is designed to make it easily extended to other version-control +systems: all VCS-specific components are in separate directories like +src/git/ . The top-level `versioneer.py` script is assembled from these +components by running make-versioneer.py . In the future, make-versioneer.py +will take a VCS name as an argument, and will construct a version of +`versioneer.py` that is specific to the given VCS. It might also take the +configuration arguments that are currently provided manually during +installation by editing setup.py . Alternatively, it might go the other +direction and include code from all supported VCS systems, reducing the +number of intermediate scripts. + + +## License + +To make Versioneer easier to embed, all its code is dedicated to the public +domain. The `_version.py` that it creates is also in the public domain. +Specifically, both are released under the Creative Commons "Public Domain +Dedication" license (CC0-1.0), as described in +https://creativecommons.org/publicdomain/zero/1.0/ . + +""" + +from __future__ import print_function +try: + import configparser +except ImportError: + import ConfigParser as configparser +import errno +import json +import os +import re +import subprocess +import sys + + +class VersioneerConfig: + """Container for Versioneer configuration parameters.""" + + +def get_root(): + """Get the project root directory. + + We require that all commands are run from the project root, i.e. the + directory that contains setup.py, setup.cfg, and versioneer.py . + """ + root = os.path.realpath(os.path.abspath(os.getcwd())) + setup_py = os.path.join(root, "setup.py") + versioneer_py = os.path.join(root, "versioneer.py") + if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): + # allow 'python path/to/setup.py COMMAND' + root = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0]))) + setup_py = os.path.join(root, "setup.py") + versioneer_py = os.path.join(root, "versioneer.py") + if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): + err = ("Versioneer was unable to run the project root directory. " + "Versioneer requires setup.py to be executed from " + "its immediate directory (like 'python setup.py COMMAND'), " + "or in a way that lets it use sys.argv[0] to find the root " + "(like 'python path/to/setup.py COMMAND').") + raise VersioneerBadRootError(err) + try: + # Certain runtime workflows (setup.py install/develop in a setuptools + # tree) execute all dependencies in a single python process, so + # "versioneer" may be imported multiple times, and python's shared + # module-import table will cache the first one. So we can't use + # os.path.dirname(__file__), as that will find whichever + # versioneer.py was first imported, even in later projects. + me = os.path.realpath(os.path.abspath(__file__)) + me_dir = os.path.normcase(os.path.splitext(me)[0]) + vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) + if me_dir != vsr_dir: + print("Warning: build in %s is using versioneer.py from %s" + % (os.path.dirname(me), versioneer_py)) + except NameError: + pass + return root + + +def get_config_from_root(root): + """Read the project setup.cfg file to determine Versioneer config.""" + # This might raise EnvironmentError (if setup.cfg is missing), or + # configparser.NoSectionError (if it lacks a [versioneer] section), or + # configparser.NoOptionError (if it lacks "VCS="). See the docstring at + # the top of versioneer.py for instructions on writing your setup.cfg . + setup_cfg = os.path.join(root, "setup.cfg") + parser = configparser.SafeConfigParser() + with open(setup_cfg, "r") as f: + parser.readfp(f) + VCS = parser.get("versioneer", "VCS") # mandatory + + def get(parser, name): + if parser.has_option("versioneer", name): + return parser.get("versioneer", name) + return None + cfg = VersioneerConfig() + cfg.VCS = VCS + cfg.style = get(parser, "style") or "" + cfg.versionfile_source = get(parser, "versionfile_source") + cfg.versionfile_build = get(parser, "versionfile_build") + cfg.tag_prefix = get(parser, "tag_prefix") + if cfg.tag_prefix in ("''", '""'): + cfg.tag_prefix = "" + cfg.parentdir_prefix = get(parser, "parentdir_prefix") + cfg.verbose = get(parser, "verbose") + return cfg + + +class NotThisMethod(Exception): + """Exception raised if a method is not valid for the current scenario.""" + + +# these dictionaries contain VCS-specific tools +LONG_VERSION_PY = {} +HANDLERS = {} + + +def register_vcs_handler(vcs, method): # decorator + """Decorator to mark a method as the handler for a particular VCS.""" + def decorate(f): + """Store f in HANDLERS[vcs][method].""" + if vcs not in HANDLERS: + HANDLERS[vcs] = {} + HANDLERS[vcs][method] = f + return f + return decorate + + +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, + env=None): + """Call the given command(s).""" + assert isinstance(commands, list) + p = None + for c in commands: + try: + dispcmd = str([c] + args) + # remember shell=False, so use git.cmd on windows, not just git + p = subprocess.Popen([c] + args, cwd=cwd, env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr + else None)) + break + except EnvironmentError: + e = sys.exc_info()[1] + if e.errno == errno.ENOENT: + continue + if verbose: + print("unable to run %s" % dispcmd) + print(e) + return None, None + else: + if verbose: + print("unable to find command, tried %s" % (commands,)) + return None, None + stdout = p.communicate()[0].strip() + if sys.version_info[0] >= 3: + stdout = stdout.decode() + if p.returncode != 0: + if verbose: + print("unable to run %s (error)" % dispcmd) + print("stdout was %s" % stdout) + return None, p.returncode + return stdout, p.returncode + + +LONG_VERSION_PY['git'] = ''' +# This file helps to compute a version number in source trees obtained from +# git-archive tarball (such as those provided by githubs download-from-tag +# feature). Distribution tarballs (built by setup.py sdist) and build +# directories (produced by setup.py build) will contain a much shorter file +# that just contains the computed version number. + +# This file is released into the public domain. Generated by +# versioneer-0.18 (https://github.com/warner/python-versioneer) + +"""Git implementation of _version.py.""" + +import errno +import os +import re +import subprocess +import sys + + +def get_keywords(): + """Get the keywords needed to look up the version information.""" + # these strings will be replaced by git during git-archive. + # setup.py/versioneer.py will grep for the variable names, so they must + # each be defined on a line of their own. _version.py will just call + # get_keywords(). + git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s" + git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s" + git_date = "%(DOLLAR)sFormat:%%ci%(DOLLAR)s" + keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} + return keywords + + +class VersioneerConfig: + """Container for Versioneer configuration parameters.""" + + +def get_config(): + """Create, populate and return the VersioneerConfig() object.""" + # these strings are filled in when 'setup.py versioneer' creates + # _version.py + cfg = VersioneerConfig() + cfg.VCS = "git" + cfg.style = "%(STYLE)s" + cfg.tag_prefix = "%(TAG_PREFIX)s" + cfg.parentdir_prefix = "%(PARENTDIR_PREFIX)s" + cfg.versionfile_source = "%(VERSIONFILE_SOURCE)s" + cfg.verbose = False + return cfg + + +class NotThisMethod(Exception): + """Exception raised if a method is not valid for the current scenario.""" + + +LONG_VERSION_PY = {} +HANDLERS = {} + + +def register_vcs_handler(vcs, method): # decorator + """Decorator to mark a method as the handler for a particular VCS.""" + def decorate(f): + """Store f in HANDLERS[vcs][method].""" + if vcs not in HANDLERS: + HANDLERS[vcs] = {} + HANDLERS[vcs][method] = f + return f + return decorate + + +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, + env=None): + """Call the given command(s).""" + assert isinstance(commands, list) + p = None + for c in commands: + try: + dispcmd = str([c] + args) + # remember shell=False, so use git.cmd on windows, not just git + p = subprocess.Popen([c] + args, cwd=cwd, env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr + else None)) + break + except EnvironmentError: + e = sys.exc_info()[1] + if e.errno == errno.ENOENT: + continue + if verbose: + print("unable to run %%s" %% dispcmd) + print(e) + return None, None + else: + if verbose: + print("unable to find command, tried %%s" %% (commands,)) + return None, None + stdout = p.communicate()[0].strip() + if sys.version_info[0] >= 3: + stdout = stdout.decode() + if p.returncode != 0: + if verbose: + print("unable to run %%s (error)" %% dispcmd) + print("stdout was %%s" %% stdout) + return None, p.returncode + return stdout, p.returncode + + +def versions_from_parentdir(parentdir_prefix, root, verbose): + """Try to determine the version from the parent directory name. + + Source tarballs conventionally unpack into a directory that includes both + the project name and a version string. We will also support searching up + two directory levels for an appropriately named parent directory + """ + rootdirs = [] + + for i in range(3): + dirname = os.path.basename(root) + if dirname.startswith(parentdir_prefix): + return {"version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, "error": None, "date": None} + else: + rootdirs.append(root) + root = os.path.dirname(root) # up a level + + if verbose: + print("Tried directories %%s but none started with prefix %%s" %% + (str(rootdirs), parentdir_prefix)) + raise NotThisMethod("rootdir doesn't start with parentdir_prefix") + + +@register_vcs_handler("git", "get_keywords") +def git_get_keywords(versionfile_abs): + """Extract version information from the given file.""" + # the code embedded in _version.py can just fetch the value of these + # keywords. When used from setup.py, we don't want to import _version.py, + # so we do it with a regexp instead. This function is not used from + # _version.py. + keywords = {} + try: + f = open(versionfile_abs, "r") + for line in f.readlines(): + if line.strip().startswith("git_refnames ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["refnames"] = mo.group(1) + if line.strip().startswith("git_full ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["full"] = mo.group(1) + if line.strip().startswith("git_date ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["date"] = mo.group(1) + f.close() + except EnvironmentError: + pass + return keywords + + +@register_vcs_handler("git", "keywords") +def git_versions_from_keywords(keywords, tag_prefix, verbose): + """Get version information from git keywords.""" + if not keywords: + raise NotThisMethod("no keywords at all, weird") + date = keywords.get("date") + if date is not None: + # git-2.2.0 added "%%cI", which expands to an ISO-8601 -compliant + # datestamp. However we prefer "%%ci" (which expands to an "ISO-8601 + # -like" string, which we must then edit to make compliant), because + # it's been around since git-1.5.3, and it's too difficult to + # discover which version we're using, or to work around using an + # older one. + date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) + refnames = keywords["refnames"].strip() + if refnames.startswith("$Format"): + if verbose: + print("keywords are unexpanded, not using") + raise NotThisMethod("unexpanded keywords, not a git-archive tarball") + refs = set([r.strip() for r in refnames.strip("()").split(",")]) + # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of + # just "foo-1.0". If we see a "tag: " prefix, prefer those. + TAG = "tag: " + tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + if not tags: + # Either we're using git < 1.8.3, or there really are no tags. We use + # a heuristic: assume all version tags have a digit. The old git %%d + # expansion behaves like git log --decorate=short and strips out the + # refs/heads/ and refs/tags/ prefixes that would let us distinguish + # between branches and tags. By ignoring refnames without digits, we + # filter out many common branch names like "release" and + # "stabilization", as well as "HEAD" and "master". + tags = set([r for r in refs if re.search(r'\d', r)]) + if verbose: + print("discarding '%%s', no digits" %% ",".join(refs - tags)) + if verbose: + print("likely tags: %%s" %% ",".join(sorted(tags))) + for ref in sorted(tags): + # sorting will prefer e.g. "2.0" over "2.0rc1" + if ref.startswith(tag_prefix): + r = ref[len(tag_prefix):] + if verbose: + print("picking %%s" %% r) + return {"version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": None, + "date": date} + # no suitable tags, so version is "0+unknown", but full hex is still there + if verbose: + print("no suitable tags, using unknown + full revision id") + return {"version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": "no suitable tags", "date": None} + + +@register_vcs_handler("git", "pieces_from_vcs") +def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): + """Get version from 'git describe' in the root of the source tree. + + This only gets called if the git-archive 'subst' keywords were *not* + expanded, and _version.py hasn't already been rewritten with a short + version string, meaning we're inside a checked out source tree. + """ + GITS = ["git"] + if sys.platform == "win32": + GITS = ["git.cmd", "git.exe"] + + out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, + hide_stderr=True) + if rc != 0: + if verbose: + print("Directory %%s not under git control" %% root) + raise NotThisMethod("'git rev-parse --git-dir' returned error") + + # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] + # if there isn't one, this yields HEX[-dirty] (no NUM) + describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", + "--always", "--long", + "--match", "%%s*" %% tag_prefix], + cwd=root) + # --long was added in git-1.5.5 + if describe_out is None: + raise NotThisMethod("'git describe' failed") + describe_out = describe_out.strip() + full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) + if full_out is None: + raise NotThisMethod("'git rev-parse' failed") + full_out = full_out.strip() + + pieces = {} + pieces["long"] = full_out + pieces["short"] = full_out[:7] # maybe improved later + pieces["error"] = None + + # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] + # TAG might have hyphens. + git_describe = describe_out + + # look for -dirty suffix + dirty = git_describe.endswith("-dirty") + pieces["dirty"] = dirty + if dirty: + git_describe = git_describe[:git_describe.rindex("-dirty")] + + # now we have TAG-NUM-gHEX or HEX + + if "-" in git_describe: + # TAG-NUM-gHEX + mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + if not mo: + # unparseable. Maybe git-describe is misbehaving? + pieces["error"] = ("unable to parse git-describe output: '%%s'" + %% describe_out) + return pieces + + # tag + full_tag = mo.group(1) + if not full_tag.startswith(tag_prefix): + if verbose: + fmt = "tag '%%s' doesn't start with prefix '%%s'" + print(fmt %% (full_tag, tag_prefix)) + pieces["error"] = ("tag '%%s' doesn't start with prefix '%%s'" + %% (full_tag, tag_prefix)) + return pieces + pieces["closest-tag"] = full_tag[len(tag_prefix):] + + # distance: number of commits since tag + pieces["distance"] = int(mo.group(2)) + + # commit: short hex revision ID + pieces["short"] = mo.group(3) + + else: + # HEX: no tags + pieces["closest-tag"] = None + count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], + cwd=root) + pieces["distance"] = int(count_out) # total number of commits + + # commit date: see ISO-8601 comment in git_versions_from_keywords() + date = run_command(GITS, ["show", "-s", "--format=%%ci", "HEAD"], + cwd=root)[0].strip() + pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) + + return pieces + + +def plus_or_dot(pieces): + """Return a + if we don't already have one, else return a .""" + if "+" in pieces.get("closest-tag", ""): + return "." + return "+" + + +def render_pep440(pieces): + """Build up version string, with post-release "local version identifier". + + Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you + get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty + + Exceptions: + 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += plus_or_dot(pieces) + rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + else: + # exception #1 + rendered = "0+untagged.%%d.g%%s" %% (pieces["distance"], + pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + return rendered + + +def render_pep440_pre(pieces): + """TAG[.post.devDISTANCE] -- No -dirty. + + Exceptions: + 1: no tags. 0.post.devDISTANCE + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"]: + rendered += ".post.dev%%d" %% pieces["distance"] + else: + # exception #1 + rendered = "0.post.dev%%d" %% pieces["distance"] + return rendered + + +def render_pep440_post(pieces): + """TAG[.postDISTANCE[.dev0]+gHEX] . + + The ".dev0" means dirty. Note that .dev0 sorts backwards + (a dirty tree will appear "older" than the corresponding clean one), + but you shouldn't be releasing software with -dirty anyways. + + Exceptions: + 1: no tags. 0.postDISTANCE[.dev0] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += ".post%%d" %% pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + rendered += plus_or_dot(pieces) + rendered += "g%%s" %% pieces["short"] + else: + # exception #1 + rendered = "0.post%%d" %% pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + rendered += "+g%%s" %% pieces["short"] + return rendered + + +def render_pep440_old(pieces): + """TAG[.postDISTANCE[.dev0]] . + + The ".dev0" means dirty. + + Eexceptions: + 1: no tags. 0.postDISTANCE[.dev0] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += ".post%%d" %% pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + else: + # exception #1 + rendered = "0.post%%d" %% pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + return rendered + + +def render_git_describe(pieces): + """TAG[-DISTANCE-gHEX][-dirty]. + + Like 'git describe --tags --dirty --always'. + + Exceptions: + 1: no tags. HEX[-dirty] (note: no 'g' prefix) + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"]: + rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) + else: + # exception #1 + rendered = pieces["short"] + if pieces["dirty"]: + rendered += "-dirty" + return rendered + + +def render_git_describe_long(pieces): + """TAG-DISTANCE-gHEX[-dirty]. + + Like 'git describe --tags --dirty --always -long'. + The distance/hash is unconditional. + + Exceptions: + 1: no tags. HEX[-dirty] (note: no 'g' prefix) + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) + else: + # exception #1 + rendered = pieces["short"] + if pieces["dirty"]: + rendered += "-dirty" + return rendered + + +def render(pieces, style): + """Render the given version pieces into the requested style.""" + if pieces["error"]: + return {"version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None} + + if not style or style == "default": + style = "pep440" # the default + + if style == "pep440": + rendered = render_pep440(pieces) + elif style == "pep440-pre": + rendered = render_pep440_pre(pieces) + elif style == "pep440-post": + rendered = render_pep440_post(pieces) + elif style == "pep440-old": + rendered = render_pep440_old(pieces) + elif style == "git-describe": + rendered = render_git_describe(pieces) + elif style == "git-describe-long": + rendered = render_git_describe_long(pieces) + else: + raise ValueError("unknown style '%%s'" %% style) + + return {"version": rendered, "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], "error": None, + "date": pieces.get("date")} + + +def get_versions(): + """Get version information or return default if unable to do so.""" + # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have + # __file__, we can work backwards from there to the root. Some + # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which + # case we can only use expanded keywords. + + cfg = get_config() + verbose = cfg.verbose + + try: + return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, + verbose) + except NotThisMethod: + pass + + try: + root = os.path.realpath(__file__) + # versionfile_source is the relative path from the top of the source + # tree (where the .git directory might live) to this file. Invert + # this to find the root from __file__. + for i in cfg.versionfile_source.split('/'): + root = os.path.dirname(root) + except NameError: + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to find root of source tree", + "date": None} + + try: + pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) + return render(pieces, cfg.style) + except NotThisMethod: + pass + + try: + if cfg.parentdir_prefix: + return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) + except NotThisMethod: + pass + + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", "date": None} +''' + + +@register_vcs_handler("git", "get_keywords") +def git_get_keywords(versionfile_abs): + """Extract version information from the given file.""" + # the code embedded in _version.py can just fetch the value of these + # keywords. When used from setup.py, we don't want to import _version.py, + # so we do it with a regexp instead. This function is not used from + # _version.py. + keywords = {} + try: + f = open(versionfile_abs, "r") + for line in f.readlines(): + if line.strip().startswith("git_refnames ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["refnames"] = mo.group(1) + if line.strip().startswith("git_full ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["full"] = mo.group(1) + if line.strip().startswith("git_date ="): + mo = re.search(r'=\s*"(.*)"', line) + if mo: + keywords["date"] = mo.group(1) + f.close() + except EnvironmentError: + pass + return keywords + + +@register_vcs_handler("git", "keywords") +def git_versions_from_keywords(keywords, tag_prefix, verbose): + """Get version information from git keywords.""" + if not keywords: + raise NotThisMethod("no keywords at all, weird") + date = keywords.get("date") + if date is not None: + # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant + # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 + # -like" string, which we must then edit to make compliant), because + # it's been around since git-1.5.3, and it's too difficult to + # discover which version we're using, or to work around using an + # older one. + date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) + refnames = keywords["refnames"].strip() + if refnames.startswith("$Format"): + if verbose: + print("keywords are unexpanded, not using") + raise NotThisMethod("unexpanded keywords, not a git-archive tarball") + refs = set([r.strip() for r in refnames.strip("()").split(",")]) + # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of + # just "foo-1.0". If we see a "tag: " prefix, prefer those. + TAG = "tag: " + tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + if not tags: + # Either we're using git < 1.8.3, or there really are no tags. We use + # a heuristic: assume all version tags have a digit. The old git %d + # expansion behaves like git log --decorate=short and strips out the + # refs/heads/ and refs/tags/ prefixes that would let us distinguish + # between branches and tags. By ignoring refnames without digits, we + # filter out many common branch names like "release" and + # "stabilization", as well as "HEAD" and "master". + tags = set([r for r in refs if re.search(r'\d', r)]) + if verbose: + print("discarding '%s', no digits" % ",".join(refs - tags)) + if verbose: + print("likely tags: %s" % ",".join(sorted(tags))) + for ref in sorted(tags): + # sorting will prefer e.g. "2.0" over "2.0rc1" + if ref.startswith(tag_prefix): + r = ref[len(tag_prefix):] + if verbose: + print("picking %s" % r) + return {"version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": None, + "date": date} + # no suitable tags, so version is "0+unknown", but full hex is still there + if verbose: + print("no suitable tags, using unknown + full revision id") + return {"version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": "no suitable tags", "date": None} + + +@register_vcs_handler("git", "pieces_from_vcs") +def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): + """Get version from 'git describe' in the root of the source tree. + + This only gets called if the git-archive 'subst' keywords were *not* + expanded, and _version.py hasn't already been rewritten with a short + version string, meaning we're inside a checked out source tree. + """ + GITS = ["git"] + if sys.platform == "win32": + GITS = ["git.cmd", "git.exe"] + + out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, + hide_stderr=True) + if rc != 0: + if verbose: + print("Directory %s not under git control" % root) + raise NotThisMethod("'git rev-parse --git-dir' returned error") + + # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] + # if there isn't one, this yields HEX[-dirty] (no NUM) + describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", + "--always", "--long", + "--match", "%s*" % tag_prefix], + cwd=root) + # --long was added in git-1.5.5 + if describe_out is None: + raise NotThisMethod("'git describe' failed") + describe_out = describe_out.strip() + full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) + if full_out is None: + raise NotThisMethod("'git rev-parse' failed") + full_out = full_out.strip() + + pieces = {} + pieces["long"] = full_out + pieces["short"] = full_out[:7] # maybe improved later + pieces["error"] = None + + # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] + # TAG might have hyphens. + git_describe = describe_out + + # look for -dirty suffix + dirty = git_describe.endswith("-dirty") + pieces["dirty"] = dirty + if dirty: + git_describe = git_describe[:git_describe.rindex("-dirty")] + + # now we have TAG-NUM-gHEX or HEX + + if "-" in git_describe: + # TAG-NUM-gHEX + mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + if not mo: + # unparseable. Maybe git-describe is misbehaving? + pieces["error"] = ("unable to parse git-describe output: '%s'" + % describe_out) + return pieces + + # tag + full_tag = mo.group(1) + if not full_tag.startswith(tag_prefix): + if verbose: + fmt = "tag '%s' doesn't start with prefix '%s'" + print(fmt % (full_tag, tag_prefix)) + pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" + % (full_tag, tag_prefix)) + return pieces + pieces["closest-tag"] = full_tag[len(tag_prefix):] + + # distance: number of commits since tag + pieces["distance"] = int(mo.group(2)) + + # commit: short hex revision ID + pieces["short"] = mo.group(3) + + else: + # HEX: no tags + pieces["closest-tag"] = None + count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], + cwd=root) + pieces["distance"] = int(count_out) # total number of commits + + # commit date: see ISO-8601 comment in git_versions_from_keywords() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], + cwd=root)[0].strip() + pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) + + return pieces + + +def do_vcs_install(manifest_in, versionfile_source, ipy): + """Git-specific installation logic for Versioneer. + + For Git, this means creating/changing .gitattributes to mark _version.py + for export-subst keyword substitution. + """ + GITS = ["git"] + if sys.platform == "win32": + GITS = ["git.cmd", "git.exe"] + files = [manifest_in, versionfile_source] + if ipy: + files.append(ipy) + try: + me = __file__ + if me.endswith(".pyc") or me.endswith(".pyo"): + me = os.path.splitext(me)[0] + ".py" + versioneer_file = os.path.relpath(me) + except NameError: + versioneer_file = "versioneer.py" + files.append(versioneer_file) + present = False + try: + f = open(".gitattributes", "r") + for line in f.readlines(): + if line.strip().startswith(versionfile_source): + if "export-subst" in line.strip().split()[1:]: + present = True + f.close() + except EnvironmentError: + pass + if not present: + f = open(".gitattributes", "a+") + f.write("%s export-subst\n" % versionfile_source) + f.close() + files.append(".gitattributes") + run_command(GITS, ["add", "--"] + files) + + +def versions_from_parentdir(parentdir_prefix, root, verbose): + """Try to determine the version from the parent directory name. + + Source tarballs conventionally unpack into a directory that includes both + the project name and a version string. We will also support searching up + two directory levels for an appropriately named parent directory + """ + rootdirs = [] + + for i in range(3): + dirname = os.path.basename(root) + if dirname.startswith(parentdir_prefix): + return {"version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, "error": None, "date": None} + else: + rootdirs.append(root) + root = os.path.dirname(root) # up a level + + if verbose: + print("Tried directories %s but none started with prefix %s" % + (str(rootdirs), parentdir_prefix)) + raise NotThisMethod("rootdir doesn't start with parentdir_prefix") + + +SHORT_VERSION_PY = """ +# This file was generated by 'versioneer.py' (0.18) from +# revision-control system data, or from the parent directory name of an +# unpacked source archive. Distribution tarballs contain a pre-generated copy +# of this file. + +import json + +version_json = ''' +%s +''' # END VERSION_JSON + + +def get_versions(): + return json.loads(version_json) +""" + + +def versions_from_file(filename): + """Try to determine the version from _version.py if present.""" + try: + with open(filename) as f: + contents = f.read() + except EnvironmentError: + raise NotThisMethod("unable to read _version.py") + mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", + contents, re.M | re.S) + if not mo: + mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", + contents, re.M | re.S) + if not mo: + raise NotThisMethod("no version_json in _version.py") + return json.loads(mo.group(1)) + + +def write_to_version_file(filename, versions): + """Write the given version number to the given _version.py file.""" + os.unlink(filename) + contents = json.dumps(versions, sort_keys=True, + indent=1, separators=(",", ": ")) + with open(filename, "w") as f: + f.write(SHORT_VERSION_PY % contents) + + print("set %s to '%s'" % (filename, versions["version"])) + + +def plus_or_dot(pieces): + """Return a + if we don't already have one, else return a .""" + if "+" in pieces.get("closest-tag", ""): + return "." + return "+" + + +def render_pep440(pieces): + """Build up version string, with post-release "local version identifier". + + Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you + get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty + + Exceptions: + 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += plus_or_dot(pieces) + rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + else: + # exception #1 + rendered = "0+untagged.%d.g%s" % (pieces["distance"], + pieces["short"]) + if pieces["dirty"]: + rendered += ".dirty" + return rendered + + +def render_pep440_pre(pieces): + """TAG[.post.devDISTANCE] -- No -dirty. + + Exceptions: + 1: no tags. 0.post.devDISTANCE + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"]: + rendered += ".post.dev%d" % pieces["distance"] + else: + # exception #1 + rendered = "0.post.dev%d" % pieces["distance"] + return rendered + + +def render_pep440_post(pieces): + """TAG[.postDISTANCE[.dev0]+gHEX] . + + The ".dev0" means dirty. Note that .dev0 sorts backwards + (a dirty tree will appear "older" than the corresponding clean one), + but you shouldn't be releasing software with -dirty anyways. + + Exceptions: + 1: no tags. 0.postDISTANCE[.dev0] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += ".post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + rendered += plus_or_dot(pieces) + rendered += "g%s" % pieces["short"] + else: + # exception #1 + rendered = "0.post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + rendered += "+g%s" % pieces["short"] + return rendered + + +def render_pep440_old(pieces): + """TAG[.postDISTANCE[.dev0]] . + + The ".dev0" means dirty. + + Eexceptions: + 1: no tags. 0.postDISTANCE[.dev0] + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"] or pieces["dirty"]: + rendered += ".post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + else: + # exception #1 + rendered = "0.post%d" % pieces["distance"] + if pieces["dirty"]: + rendered += ".dev0" + return rendered + + +def render_git_describe(pieces): + """TAG[-DISTANCE-gHEX][-dirty]. + + Like 'git describe --tags --dirty --always'. + + Exceptions: + 1: no tags. HEX[-dirty] (note: no 'g' prefix) + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + if pieces["distance"]: + rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) + else: + # exception #1 + rendered = pieces["short"] + if pieces["dirty"]: + rendered += "-dirty" + return rendered + + +def render_git_describe_long(pieces): + """TAG-DISTANCE-gHEX[-dirty]. + + Like 'git describe --tags --dirty --always -long'. + The distance/hash is unconditional. + + Exceptions: + 1: no tags. HEX[-dirty] (note: no 'g' prefix) + """ + if pieces["closest-tag"]: + rendered = pieces["closest-tag"] + rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) + else: + # exception #1 + rendered = pieces["short"] + if pieces["dirty"]: + rendered += "-dirty" + return rendered + + +def render(pieces, style): + """Render the given version pieces into the requested style.""" + if pieces["error"]: + return {"version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None} + + if not style or style == "default": + style = "pep440" # the default + + if style == "pep440": + rendered = render_pep440(pieces) + elif style == "pep440-pre": + rendered = render_pep440_pre(pieces) + elif style == "pep440-post": + rendered = render_pep440_post(pieces) + elif style == "pep440-old": + rendered = render_pep440_old(pieces) + elif style == "git-describe": + rendered = render_git_describe(pieces) + elif style == "git-describe-long": + rendered = render_git_describe_long(pieces) + else: + raise ValueError("unknown style '%s'" % style) + + return {"version": rendered, "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], "error": None, + "date": pieces.get("date")} + + +class VersioneerBadRootError(Exception): + """The project root directory is unknown or missing key files.""" + + +def get_versions(verbose=False): + """Get the project version from whatever source is available. + + Returns dict with two keys: 'version' and 'full'. + """ + if "versioneer" in sys.modules: + # see the discussion in cmdclass.py:get_cmdclass() + del sys.modules["versioneer"] + + root = get_root() + cfg = get_config_from_root(root) + + assert cfg.VCS is not None, "please set [versioneer]VCS= in setup.cfg" + handlers = HANDLERS.get(cfg.VCS) + assert handlers, "unrecognized VCS '%s'" % cfg.VCS + verbose = verbose or cfg.verbose + assert cfg.versionfile_source is not None, \ + "please set versioneer.versionfile_source" + assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" + + versionfile_abs = os.path.join(root, cfg.versionfile_source) + + # extract version from first of: _version.py, VCS command (e.g. 'git + # describe'), parentdir. This is meant to work for developers using a + # source checkout, for users of a tarball created by 'setup.py sdist', + # and for users of a tarball/zipball created by 'git archive' or github's + # download-from-tag feature or the equivalent in other VCSes. + + get_keywords_f = handlers.get("get_keywords") + from_keywords_f = handlers.get("keywords") + if get_keywords_f and from_keywords_f: + try: + keywords = get_keywords_f(versionfile_abs) + ver = from_keywords_f(keywords, cfg.tag_prefix, verbose) + if verbose: + print("got version from expanded keyword %s" % ver) + return ver + except NotThisMethod: + pass + + try: + ver = versions_from_file(versionfile_abs) + if verbose: + print("got version from file %s %s" % (versionfile_abs, ver)) + return ver + except NotThisMethod: + pass + + from_vcs_f = handlers.get("pieces_from_vcs") + if from_vcs_f: + try: + pieces = from_vcs_f(cfg.tag_prefix, root, verbose) + ver = render(pieces, cfg.style) + if verbose: + print("got version from VCS %s" % ver) + return ver + except NotThisMethod: + pass + + try: + if cfg.parentdir_prefix: + ver = versions_from_parentdir(cfg.parentdir_prefix, root, verbose) + if verbose: + print("got version from parentdir %s" % ver) + return ver + except NotThisMethod: + pass + + if verbose: + print("unable to compute version") + + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, "error": "unable to compute version", + "date": None} + + +def get_version(): + """Get the short version string for this project.""" + return get_versions()["version"] + + +def get_cmdclass(): + """Get the custom setuptools/distutils subclasses used by Versioneer.""" + if "versioneer" in sys.modules: + del sys.modules["versioneer"] + # this fixes the "python setup.py develop" case (also 'install' and + # 'easy_install .'), in which subdependencies of the main project are + # built (using setup.py bdist_egg) in the same python process. Assume + # a main project A and a dependency B, which use different versions + # of Versioneer. A's setup.py imports A's Versioneer, leaving it in + # sys.modules by the time B's setup.py is executed, causing B to run + # with the wrong versioneer. Setuptools wraps the sub-dep builds in a + # sandbox that restores sys.modules to it's pre-build state, so the + # parent is protected against the child's "import versioneer". By + # removing ourselves from sys.modules here, before the child build + # happens, we protect the child from the parent's versioneer too. + # Also see https://github.com/warner/python-versioneer/issues/52 + + cmds = {} + + # we add "version" to both distutils and setuptools + from distutils.core import Command + + class cmd_version(Command): + description = "report generated version string" + user_options = [] + boolean_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + vers = get_versions(verbose=True) + print("Version: %s" % vers["version"]) + print(" full-revisionid: %s" % vers.get("full-revisionid")) + print(" dirty: %s" % vers.get("dirty")) + print(" date: %s" % vers.get("date")) + if vers["error"]: + print(" error: %s" % vers["error"]) + cmds["version"] = cmd_version + + # we override "build_py" in both distutils and setuptools + # + # most invocation pathways end up running build_py: + # distutils/build -> build_py + # distutils/install -> distutils/build ->.. + # setuptools/bdist_wheel -> distutils/install ->.. + # setuptools/bdist_egg -> distutils/install_lib -> build_py + # setuptools/install -> bdist_egg ->.. + # setuptools/develop -> ? + # pip install: + # copies source tree to a tempdir before running egg_info/etc + # if .git isn't copied too, 'git describe' will fail + # then does setup.py bdist_wheel, or sometimes setup.py install + # setup.py egg_info -> ? + + # we override different "build_py" commands for both environments + if "setuptools" in sys.modules: + from setuptools.command.build_py import build_py as _build_py + else: + from distutils.command.build_py import build_py as _build_py + + class cmd_build_py(_build_py): + def run(self): + root = get_root() + cfg = get_config_from_root(root) + versions = get_versions() + _build_py.run(self) + # now locate _version.py in the new build/ directory and replace + # it with an updated value + if cfg.versionfile_build: + target_versionfile = os.path.join(self.build_lib, + cfg.versionfile_build) + print("UPDATING %s" % target_versionfile) + write_to_version_file(target_versionfile, versions) + cmds["build_py"] = cmd_build_py + + if "cx_Freeze" in sys.modules: # cx_freeze enabled? + from cx_Freeze.dist import build_exe as _build_exe + # nczeczulin reports that py2exe won't like the pep440-style string + # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. + # setup(console=[{ + # "version": versioneer.get_version().split("+", 1)[0], # FILEVERSION + # "product_version": versioneer.get_version(), + # ... + + class cmd_build_exe(_build_exe): + def run(self): + root = get_root() + cfg = get_config_from_root(root) + versions = get_versions() + target_versionfile = cfg.versionfile_source + print("UPDATING %s" % target_versionfile) + write_to_version_file(target_versionfile, versions) + + _build_exe.run(self) + os.unlink(target_versionfile) + with open(cfg.versionfile_source, "w") as f: + LONG = LONG_VERSION_PY[cfg.VCS] + f.write(LONG % + {"DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) + cmds["build_exe"] = cmd_build_exe + del cmds["build_py"] + + if 'py2exe' in sys.modules: # py2exe enabled? + try: + from py2exe.distutils_buildexe import py2exe as _py2exe # py3 + except ImportError: + from py2exe.build_exe import py2exe as _py2exe # py2 + + class cmd_py2exe(_py2exe): + def run(self): + root = get_root() + cfg = get_config_from_root(root) + versions = get_versions() + target_versionfile = cfg.versionfile_source + print("UPDATING %s" % target_versionfile) + write_to_version_file(target_versionfile, versions) + + _py2exe.run(self) + os.unlink(target_versionfile) + with open(cfg.versionfile_source, "w") as f: + LONG = LONG_VERSION_PY[cfg.VCS] + f.write(LONG % + {"DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) + cmds["py2exe"] = cmd_py2exe + + # we override different "sdist" commands for both environments + if "setuptools" in sys.modules: + from setuptools.command.sdist import sdist as _sdist + else: + from distutils.command.sdist import sdist as _sdist + + class cmd_sdist(_sdist): + def run(self): + versions = get_versions() + self._versioneer_generated_versions = versions + # unless we update this, the command will keep using the old + # version + self.distribution.metadata.version = versions["version"] + return _sdist.run(self) + + def make_release_tree(self, base_dir, files): + root = get_root() + cfg = get_config_from_root(root) + _sdist.make_release_tree(self, base_dir, files) + # now locate _version.py in the new base_dir directory + # (remembering that it may be a hardlink) and replace it with an + # updated value + target_versionfile = os.path.join(base_dir, cfg.versionfile_source) + print("UPDATING %s" % target_versionfile) + write_to_version_file(target_versionfile, + self._versioneer_generated_versions) + cmds["sdist"] = cmd_sdist + + return cmds + + +CONFIG_ERROR = """ +setup.cfg is missing the necessary Versioneer configuration. You need +a section like: + + [versioneer] + VCS = git + style = pep440 + versionfile_source = src/myproject/_version.py + versionfile_build = myproject/_version.py + tag_prefix = + parentdir_prefix = myproject- + +You will also need to edit your setup.py to use the results: + + import versioneer + setup(version=versioneer.get_version(), + cmdclass=versioneer.get_cmdclass(), ...) + +Please read the docstring in ./versioneer.py for configuration instructions, +edit setup.cfg, and re-run the installer or 'python versioneer.py setup'. +""" + +SAMPLE_CONFIG = """ +# See the docstring in versioneer.py for instructions. Note that you must +# re-run 'versioneer.py setup' after changing this section, and commit the +# resulting files. + +[versioneer] +#VCS = git +#style = pep440 +#versionfile_source = +#versionfile_build = +#tag_prefix = +#parentdir_prefix = + +""" + +INIT_PY_SNIPPET = """ +from ._version import get_versions +__version__ = get_versions()['version'] +del get_versions +""" + + +def do_setup(): + """Main VCS-independent setup function for installing Versioneer.""" + root = get_root() + try: + cfg = get_config_from_root(root) + except (EnvironmentError, configparser.NoSectionError, + configparser.NoOptionError) as e: + if isinstance(e, (EnvironmentError, configparser.NoSectionError)): + print("Adding sample versioneer config to setup.cfg", + file=sys.stderr) + with open(os.path.join(root, "setup.cfg"), "a") as f: + f.write(SAMPLE_CONFIG) + print(CONFIG_ERROR, file=sys.stderr) + return 1 + + print(" creating %s" % cfg.versionfile_source) + with open(cfg.versionfile_source, "w") as f: + LONG = LONG_VERSION_PY[cfg.VCS] + f.write(LONG % {"DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) + + ipy = os.path.join(os.path.dirname(cfg.versionfile_source), + "__init__.py") + if os.path.exists(ipy): + try: + with open(ipy, "r") as f: + old = f.read() + except EnvironmentError: + old = "" + if INIT_PY_SNIPPET not in old: + print(" appending to %s" % ipy) + with open(ipy, "a") as f: + f.write(INIT_PY_SNIPPET) + else: + print(" %s unmodified" % ipy) + else: + print(" %s doesn't exist, ok" % ipy) + ipy = None + + # Make sure both the top-level "versioneer.py" and versionfile_source + # (PKG/_version.py, used by runtime code) are in MANIFEST.in, so + # they'll be copied into source distributions. Pip won't be able to + # install the package without this. + manifest_in = os.path.join(root, "MANIFEST.in") + simple_includes = set() + try: + with open(manifest_in, "r") as f: + for line in f: + if line.startswith("include "): + for include in line.split()[1:]: + simple_includes.add(include) + except EnvironmentError: + pass + # That doesn't cover everything MANIFEST.in can do + # (http://docs.python.org/2/distutils/sourcedist.html#commands), so + # it might give some false negatives. Appending redundant 'include' + # lines is safe, though. + if "versioneer.py" not in simple_includes: + print(" appending 'versioneer.py' to MANIFEST.in") + with open(manifest_in, "a") as f: + f.write("include versioneer.py\n") + else: + print(" 'versioneer.py' already in MANIFEST.in") + if cfg.versionfile_source not in simple_includes: + print(" appending versionfile_source ('%s') to MANIFEST.in" % + cfg.versionfile_source) + with open(manifest_in, "a") as f: + f.write("include %s\n" % cfg.versionfile_source) + else: + print(" versionfile_source already in MANIFEST.in") + + # Make VCS-specific changes. For git, this means creating/changing + # .gitattributes to mark _version.py for export-subst keyword + # substitution. + do_vcs_install(manifest_in, cfg.versionfile_source, ipy) + return 0 + + +def scan_setup_py(): + """Validate the contents of setup.py against Versioneer's expectations.""" + found = set() + setters = False + errors = 0 + with open("setup.py", "r") as f: + for line in f.readlines(): + if "import versioneer" in line: + found.add("import") + if "versioneer.get_cmdclass()" in line: + found.add("cmdclass") + if "versioneer.get_version()" in line: + found.add("get_version") + if "versioneer.VCS" in line: + setters = True + if "versioneer.versionfile_source" in line: + setters = True + if len(found) != 3: + print("") + print("Your setup.py appears to be missing some important items") + print("(but I might be wrong). Please make sure it has something") + print("roughly like the following:") + print("") + print(" import versioneer") + print(" setup( version=versioneer.get_version(),") + print(" cmdclass=versioneer.get_cmdclass(), ...)") + print("") + errors += 1 + if setters: + print("You should remove lines like 'versioneer.VCS = ' and") + print("'versioneer.versionfile_source = ' . This configuration") + print("now lives in setup.cfg, and should be removed from setup.py") + print("") + errors += 1 + return errors + + +if __name__ == "__main__": + cmd = sys.argv[1] + if cmd == "setup": + errors = do_setup() + errors += scan_setup_py() + if errors: + sys.exit(1) diff --git a/external-deps/python-language-server/vscode-client/.gitignore b/external-deps/python-language-server/vscode-client/.gitignore new file mode 100644 index 00000000000..3dc9acd2bf2 --- /dev/null +++ b/external-deps/python-language-server/vscode-client/.gitignore @@ -0,0 +1,4 @@ +out +server +node_modules +.vscode-dev \ No newline at end of file diff --git a/external-deps/python-language-server/vscode-client/.vscodeignore b/external-deps/python-language-server/vscode-client/.vscodeignore new file mode 100644 index 00000000000..93e28ff2fdf --- /dev/null +++ b/external-deps/python-language-server/vscode-client/.vscodeignore @@ -0,0 +1,9 @@ +.vscode/** +typings/** +out/test/** +test/** +src/** +**/*.map +.gitignore +tsconfig.json +vsc-extension-quickstart.md diff --git a/external-deps/python-language-server/vscode-client/License.txt b/external-deps/python-language-server/vscode-client/License.txt new file mode 100644 index 00000000000..8e1db2929e4 --- /dev/null +++ b/external-deps/python-language-server/vscode-client/License.txt @@ -0,0 +1,11 @@ +Copyright (c) Microsoft Corporation + +All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/external-deps/python-language-server/vscode-client/README.md b/external-deps/python-language-server/vscode-client/README.md new file mode 100644 index 00000000000..f9f3bf4e54e --- /dev/null +++ b/external-deps/python-language-server/vscode-client/README.md @@ -0,0 +1,33 @@ +# vscode-client + +The vscode-client extension for Visual Studio Code helps you develop +and debug language servers. It lets you run multiple language servers +at once with minimal extra configuration per language. + +## Using this extension + + +1. Follow the [Develop against VS Code instructions](/../../#develop-against-vs-code) +1. Open a `.py` file and hover over text to start using the Python language server. + +To view a language server's stderr output in VSCode, select View → Output. +To debug further, see the "Hacking on this extension" section below. + +After updating the binary for a language server (during development or after an upgrade), just kill the process (e.g., `killall pyls`). +VSCode will automatically restart and reconnect to the language server process. + +> **Note for those who use VSCode as their primary editor:** Because this extension's functionality conflicts with other VSCode extensions +(e.g., showing Python hover information), the `yarn run vscode` script launches a separate instance of VSCode and stores its config in `../.vscode-dev`. +It will still show your existing extensions in the panel (which seems to be a VSCode bug), but they won't be activated. + +## Adding a language server + +Register your language server at the bottom of [`extension.ts`](src/extension.ts). + +## Hacking on this extension + +1. Run `yarn install` in this directory (`vscode-client`). +1. Open this directory by itself in Visual Studio Code. +1. Hit F5 to open a new VSCode instance in a debugger running this extension. (This is equivalent to going to the Debug pane on the left and running the "Launch Extension" task.) + +See the [Node.js example language server tutorial](https://code.visualstudio.com/docs/extensions/example-language-server) under "To test the language server" for more information. diff --git a/external-deps/python-language-server/vscode-client/ThirdPartyNotices.txt b/external-deps/python-language-server/vscode-client/ThirdPartyNotices.txt new file mode 100644 index 00000000000..80a9d602af8 --- /dev/null +++ b/external-deps/python-language-server/vscode-client/ThirdPartyNotices.txt @@ -0,0 +1,31 @@ +THIRD-PARTY SOFTWARE NOTICES AND INFORMATION +For Microsoft vscode-languageserver-node-example + +This project incorporates material from the project(s) listed below (collectively, “Third Party Code”). +Microsoft is not the original author of the Third Party Code. The original copyright notice and license +under which Microsoft received such Third Party Code are set out below. This Third Party Code is licensed +to you under their original license terms set forth below. Microsoft reserves all other rights not expressly +granted, whether by implication, estoppel or otherwise. + +1. DefinitelyTyped version 0.0.1 (https://github.com/borisyankov/DefinitelyTyped) + +This project is licensed under the MIT license. +Copyrights are respective of each contributor listed at the beginning of each definition file. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/external-deps/python-language-server/vscode-client/package.json b/external-deps/python-language-server/vscode-client/package.json new file mode 100644 index 00000000000..7e4ee59f85b --- /dev/null +++ b/external-deps/python-language-server/vscode-client/package.json @@ -0,0 +1,306 @@ +{ + "name": "pyls", + "description": "Python language server", + "author": "Sourcegraph", + "repository": "https://github.com/Microsoft/vscode-languageserver-node", + "license": "MIT", + "version": "0.0.1", + "publisher": "sqs", + "engines": { + "vscode": "^1.15.0" + }, + "categories": [ + "Other" + ], + "activationEvents": [ + "*" + ], + "contributes": { + "configuration": { + "title": "Python Language Server Configuration", + "type": "object", + "properties": { + "pyls.executable": { + "type": "string", + "default": "pyls", + "description": "Language server executable" + }, + "pyls.configurationSources": { + "type": "array", + "default": ["pycodestyle"], + "description": "List of configuration sources to use.", + "items": { + "type": "string", + "enum": ["pycodestyle", "pyflakes"] + }, + "uniqueItems": true + }, + "pyls.plugins.jedi.extra_paths": { + "type": "array", + "default": [], + "description": "Define extra paths for jedi.Script." + }, + "pyls.plugins.jedi.environment": { + "type": "string", + "default": null, + "description": "Define environment for jedi.Script and Jedi.names." + }, + "pyls.plugins.jedi_completion.enabled": { + "type": "boolean", + "default": true, + "description": "Enable or disable the plugin." + }, + "pyls.plugins.jedi_completion.include_params": { + "type": "boolean", + "default": true, + "description": "Auto-completes methods and classes with tabstops for each parameter." + }, + "pyls.plugins.jedi_completion.include_class_objects": { + "type": "boolean", + "default": true, + "description": "Adds class objects as a separate completion item." + }, + "pyls.plugins.jedi_completion.fuzzy": { + "type": "boolean", + "default": false, + "description": "Enable fuzzy when requesting autocomplete." + }, + "pyls.plugins.jedi_definition.enabled": { + "type": "boolean", + "default": true, + "description": "Enable or disable the plugin." + }, + "pyls.plugins.jedi_definition.follow_imports": { + "type": "boolean", + "default": true, + "description": "The goto call will follow imports." + }, + "pyls.plugins.jedi_definition.follow_builtin_imports": { + "type": "boolean", + "default": true, + "description": "If follow_imports is True will decide if it follow builtin imports." + }, + "pyls.plugins.jedi_hover.enabled": { + "type": "boolean", + "default": true, + "description": "Enable or disable the plugin." + }, + "pyls.plugins.jedi_references.enabled": { + "type": "boolean", + "default": true, + "description": "Enable or disable the plugin." + }, + "pyls.plugins.jedi_signature_help.enabled": { + "type": "boolean", + "default": true, + "description": "Enable or disable the plugin." + }, + "pyls.plugins.jedi_symbols.enabled": { + "type": "boolean", + "default": true, + "description": "Enable or disable the plugin." + }, + "pyls.plugins.jedi_symbols.all_scopes": { + "type": "boolean", + "default": true, + "description": "If True lists the names of all scopes instead of only the module namespace." + }, + "pyls.plugins.mccabe.enabled": { + "type": "boolean", + "default": true, + "description": "Enable or disable the plugin." + }, + "pyls.plugins.mccabe.threshold": { + "type": "number", + "default": 15, + "description": "The minimum threshold that triggers warnings about cyclomatic complexity." + }, + "pyls.plugins.preload.enabled": { + "type": "boolean", + "default": true, + "description": "Enable or disable the plugin." + }, + "pyls.plugins.preload.modules": { + "type": "array", + "default": null, + "items": { + "type": "string" + }, + "uniqueItems": true, + "description": "List of modules to import on startup" + }, + "pyls.plugins.pycodestyle.enabled": { + "type": "boolean", + "default": true, + "description": "Enable or disable the plugin." + }, + "pyls.plugins.pycodestyle.exclude": { + "type": "array", + "default": null, + "items": { + "type": "string" + }, + "uniqueItems": true, + "description": "Exclude files or directories which match these patterns." + }, + "pyls.plugins.pycodestyle.filename": { + "type": "array", + "default": null, + "items": { + "type": "string" + }, + "uniqueItems": true, + "description": "When parsing directories, only check filenames matching these patterns." + }, + "pyls.plugins.pycodestyle.select": { + "type": "array", + "default": null, + "items": { + "type": "string" + }, + "uniqueItems": true, + "description": "Select errors and warnings" + }, + "pyls.plugins.pycodestyle.ignore": { + "type": "array", + "default": null, + "items": { + "type": "string" + }, + "uniqueItems": true, + "description": "Ignore errors and warnings" + }, + "pyls.plugins.pycodestyle.hangClosing": { + "type": "boolean", + "default": null, + "description": "Hang closing bracket instead of matching indentation of opening bracket's line." + }, + "pyls.plugins.pycodestyle.maxLineLength": { + "type": "number", + "default": null, + "description": "Set maximum allowed line length." + }, + "pyls.plugins.pydocstyle.enabled": { + "type": "boolean", + "default": false, + "description": "Enable or disable the plugin." + }, + "pyls.plugins.pydocstyle.convention": { + "type": "string", + "default": null, + "enum": [ + "pep257", + "numpy" + ], + "description": "Choose the basic list of checked errors by specifying an existing convention." + }, + "pyls.plugins.pydocstyle.addIgnore": { + "type": "array", + "default": null, + "items": { + "type": "string" + }, + "uniqueItems": true, + "description": "Ignore errors and warnings in addition to the specified convention." + }, + "pyls.plugins.pydocstyle.addSelect": { + "type": "array", + "default": null, + "items": { + "type": "string" + }, + "uniqueItems": true, + "description": "Select errors and warnings in addition to the specified convention." + }, + "pyls.plugins.pydocstyle.ignore": { + "type": "array", + "default": null, + "items": { + "type": "string" + }, + "uniqueItems": true, + "description": "Ignore errors and warnings" + }, + "pyls.plugins.pydocstyle.select": { + "type": "array", + "default": null, + "items": { + "type": "string" + }, + "uniqueItems": true, + "description": "Select errors and warnings" + }, + "pyls.plugins.pydocstyle.match": { + "type": "string", + "default": "(?!test_).*\\.py", + "description": "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'." + }, + "pyls.plugins.pydocstyle.matchDir": { + "type": "string", + "default": "[^\\.].*", + "description": "Search only dirs that exactly match the given regular expression; default is to match dirs which do not begin with a dot." + }, + "pyls.plugins.pyflakes.enabled": { + "type": "boolean", + "default": true, + "description": "Enable or disable the plugin." + }, + "pyls.plugins.pylint.enabled": { + "type": "boolean", + "default": false, + "description": "Enable or disable the plugin." + }, + "pyls.plugins.pylint.args": { + "type": "array", + "default": null, + "items": { + "type": "string" + }, + "uniqueItems": false, + "description": "Arguments to pass to pylint." + }, + "pyls.plugins.rope_completion.enabled": { + "type": "boolean", + "default": true, + "description": "Enable or disable the plugin." + }, + "pyls.plugins.yapf.enabled": { + "type": "boolean", + "default": true, + "description": "Enable or disable the plugin." + }, + "pyls.rope.extensionModules": { + "type": "string", + "default": null, + "description": "Builtin and c-extension modules that are allowed to be imported and inspected by rope." + }, + "pyls.rope.ropeFolder": { + "type": "array", + "default": null, + "items": { + "type": "string" + }, + "uniqueItems": true, + "description": "The name of the folder in which rope stores project configurations and data. Pass `null` for not using such a folder at all." + } + } + } + }, + "main": "./out/extension", + "scripts": { + "vscode:prepublish": "tsc -p ./", + "compile": "tsc -watch -p ./", + "postinstall": "node ./node_modules/vscode/bin/install", + "vscode": "npm run vscode:prepublish && VSCODE=$(which code-insiders || which code || echo echo ERROR: neither the code nor code-insiders vscode executable is installed); USER=dummy-dont-share-vscode-instance $VSCODE --user-data-dir=$PWD/.vscode-dev/user-data --extensionHomePath=$PWD/.vscode-dev/extensions --extensionDevelopmentPath=$PWD $*" + }, + "devDependencies": { + "typescript": "^2.3.4", + "vscode": "^1.1.4", + "mocha": "^2.3.3", + "@types/node": "^6.0.40", + "@types/mocha": "^2.2.32" + }, + "dependencies": { + "vscode-languageclient": "^3.4.5" + } +} diff --git a/external-deps/python-language-server/vscode-client/src/extension.ts b/external-deps/python-language-server/vscode-client/src/extension.ts new file mode 100644 index 00000000000..5816f9df415 --- /dev/null +++ b/external-deps/python-language-server/vscode-client/src/extension.ts @@ -0,0 +1,51 @@ +/* -------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * ------------------------------------------------------------------------------------------ */ +'use strict'; + +import * as net from 'net'; + +import { workspace, Disposable, ExtensionContext } from 'vscode'; +import { LanguageClient, LanguageClientOptions, SettingMonitor, ServerOptions, ErrorAction, ErrorHandler, CloseAction, TransportKind } from 'vscode-languageclient'; + +function startLangServer(command: string, args: string[], documentSelector: string[]): Disposable { + const serverOptions: ServerOptions = { + command, + args, + }; + const clientOptions: LanguageClientOptions = { + documentSelector: documentSelector, + synchronize: { + configurationSection: "pyls" + } + } + return new LanguageClient(command, serverOptions, clientOptions).start(); +} + +function startLangServerTCP(addr: number, documentSelector: string[]): Disposable { + const serverOptions: ServerOptions = function() { + return new Promise((resolve, reject) => { + var client = new net.Socket(); + client.connect(addr, "127.0.0.1", function() { + resolve({ + reader: client, + writer: client + }); + }); + }); + } + + const clientOptions: LanguageClientOptions = { + documentSelector: documentSelector, + } + return new LanguageClient(`tcp lang server (port ${addr})`, serverOptions, clientOptions).start(); +} + +export function activate(context: ExtensionContext) { + const executable = workspace.getConfiguration("pyls").get("executable"); + context.subscriptions.push(startLangServer(executable, ["-vv"], ["python"])); + // For TCP server needs to be started seperately + // context.subscriptions.push(startLangServerTCP(2087, ["python"])); +} + diff --git a/external-deps/python-language-server/vscode-client/tsconfig.json b/external-deps/python-language-server/vscode-client/tsconfig.json new file mode 100644 index 00000000000..a9142181413 --- /dev/null +++ b/external-deps/python-language-server/vscode-client/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "outDir": "out", + "lib": [ "es6" ], + "sourceMap": true + }, + "exclude": [ + "node_modules", + "server" + ] +} diff --git a/external-deps/python-language-server/vscode-client/yarn.lock b/external-deps/python-language-server/vscode-client/yarn.lock new file mode 100644 index 00000000000..01b11c89726 --- /dev/null +++ b/external-deps/python-language-server/vscode-client/yarn.lock @@ -0,0 +1,1821 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/mocha@^2.2.32": + version "2.2.46" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.46.tgz#b04713f7759d1cf752effdaae7b3969e285ebc16" + +"@types/node@^6.0.40": + version "6.0.96" + resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.96.tgz#7bf0bf40d6ce51e93762cc47d010c8cc5ebb2179" + +ajv@^5.1.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +ansi-cyan@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-cyan/-/ansi-cyan-0.1.1.tgz#538ae528af8982f28ae30d86f2f17456d2609873" + dependencies: + ansi-wrap "0.1.0" + +ansi-gray@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251" + dependencies: + ansi-wrap "0.1.0" + +ansi-red@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-red/-/ansi-red-0.1.1.tgz#8c638f9d1080800a353c9c28c8a81ca4705d946c" + dependencies: + ansi-wrap "0.1.0" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +ansi-wrap@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" + +arr-diff@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-1.1.0.tgz#687c32758163588fef7de7b36fabe495eb1a399a" + dependencies: + arr-flatten "^1.0.1" + array-slice "^0.2.3" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + +arr-union@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-2.1.0.tgz#20f9eab5ec70f5c7d215b1077b1c39161d292c7d" + +array-differ@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" + +array-slice@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1, array-uniq@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.2.1, aws4@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +bcrypt-pbkdf@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + dependencies: + tweetnacl "^0.14.3" + +beeper@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +boom@4.x.x: + version "4.3.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" + dependencies: + hoek "4.x.x" + +boom@5.x.x: + version "5.2.0" + resolved "https://registry.yarnpkg.com/boom/-/boom-5.2.0.tgz#5dd9da6ee3a5f302077436290cb717d3f4a54e02" + dependencies: + hoek "4.x.x" + +brace-expansion@^1.1.7: + version "1.1.8" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +browser-stdout@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" + +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + +caseless@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + +chalk@^1.0.0, chalk@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +clone-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" + +clone-stats@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" + +clone-stats@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" + +clone@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" + +clone@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.3.tgz#298d7e2231660f40c003c2ed3140decf3f53085f" + +clone@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" + +cloneable-readable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.0.0.tgz#a6290d413f217a61232f95e458ff38418cfb0117" + dependencies: + inherits "^2.0.1" + process-nextick-args "^1.0.6" + through2 "^2.0.1" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +color-support@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + dependencies: + delayed-stream "~1.0.0" + +commander@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-0.6.1.tgz#fa68a14f6a945d54dbbe50d8cdb3320e9e3b1a06" + +commander@2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" + +commander@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" + +commander@^2.9.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +convert-source-map@^1.1.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +cryptiles@3.x.x: + version "3.1.2" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" + dependencies: + boom "5.x.x" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +dateformat@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062" + +debug@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + dependencies: + ms "0.7.1" + +debug@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + +deep-assign@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/deep-assign/-/deep-assign-1.0.0.tgz#b092743be8427dc621ea0067cdec7e70dd19f37b" + dependencies: + is-obj "^1.0.0" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +diff@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" + +diff@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" + +duplexer2@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" + dependencies: + readable-stream "~1.1.9" + +duplexer@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + +duplexify@^3.2.0: + version "3.5.3" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.3.tgz#8b5818800df92fd0125b27ab896491912858243e" + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +end-of-stream@^1.0.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + dependencies: + once "^1.4.0" + +escape-string-regexp@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" + +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +event-stream@^3.3.1, event-stream@~3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" + dependencies: + duplexer "~0.1.1" + from "~0" + map-stream "~0.1.0" + pause-stream "0.0.11" + split "0.3" + stream-combiner "~0.0.4" + through "~2.3.1" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +extend-shallow@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-1.1.4.tgz#19d6bf94dfc09d76ba711f39b872d21ff4dd9071" + dependencies: + kind-of "^1.1.0" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + +extend@^3.0.0, extend@~3.0.0, extend@~3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + +fancy-log@^1.1.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.2.tgz#f41125e3d84f2e7d89a43d06d958c8f78be16be1" + dependencies: + ansi-gray "^0.1.1" + color-support "^1.1.3" + time-stamp "^1.0.0" + +fast-deep-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + +fd-slicer@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" + dependencies: + pend "~1.2.0" + +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +first-chunk-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e" + +for-in@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + dependencies: + for-in "^1.0.1" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +form-data@~2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +from@~0: + version "0.1.7" + resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fstream@^1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob-parent@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-stream@^5.3.2: + version "5.3.5" + resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-5.3.5.tgz#a55665a9a8ccdc41915a87c701e32d4e016fad22" + dependencies: + extend "^3.0.0" + glob "^5.0.3" + glob-parent "^3.0.0" + micromatch "^2.3.7" + ordered-read-streams "^0.3.0" + through2 "^0.6.0" + to-absolute-glob "^0.1.1" + unique-stream "^2.0.2" + +glob@3.2.11: + version "3.2.11" + resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d" + dependencies: + inherits "2" + minimatch "0.3" + +glob@7.1.2, glob@^7.0.5, glob@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^5.0.3: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glogg@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.0.tgz#7fe0f199f57ac906cf512feead8f90ee4a284fc5" + dependencies: + sparkles "^1.0.0" + +graceful-fs@^4.0.0, graceful-fs@^4.1.2: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +growl@1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.3.tgz#1926ba90cf3edfe2adb4927f5880bc22c66c790f" + +growl@1.9.2: + version "1.9.2" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" + +gulp-chmod@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/gulp-chmod/-/gulp-chmod-2.0.0.tgz#00c390b928a0799b251accf631aa09e01cc6299c" + dependencies: + deep-assign "^1.0.0" + stat-mode "^0.2.0" + through2 "^2.0.0" + +gulp-filter@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/gulp-filter/-/gulp-filter-5.1.0.tgz#a05e11affb07cf7dcf41a7de1cb7b63ac3783e73" + dependencies: + multimatch "^2.0.0" + plugin-error "^0.1.2" + streamfilter "^1.0.5" + +gulp-gunzip@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gulp-gunzip/-/gulp-gunzip-1.0.0.tgz#15b741145e83a9c6f50886241b57cc5871f151a9" + dependencies: + through2 "~0.6.5" + vinyl "~0.4.6" + +gulp-remote-src@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/gulp-remote-src/-/gulp-remote-src-0.4.3.tgz#5728cfd643433dd4845ddef0969f0f971a2ab4a1" + dependencies: + event-stream "~3.3.4" + node.extend "~1.1.2" + request "~2.79.0" + through2 "~2.0.3" + vinyl "~2.0.1" + +gulp-sourcemaps@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz#b86ff349d801ceb56e1d9e7dc7bbcb4b7dee600c" + dependencies: + convert-source-map "^1.1.1" + graceful-fs "^4.1.2" + strip-bom "^2.0.0" + through2 "^2.0.0" + vinyl "^1.0.0" + +gulp-symdest@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/gulp-symdest/-/gulp-symdest-1.1.0.tgz#c165320732d192ce56fd94271ffa123234bf2ae0" + dependencies: + event-stream "^3.3.1" + mkdirp "^0.5.1" + queue "^3.1.0" + vinyl-fs "^2.4.3" + +gulp-untar@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/gulp-untar/-/gulp-untar-0.0.6.tgz#d6bdefde7e9a8e054c9f162385a0782c4be74000" + dependencies: + event-stream "~3.3.4" + gulp-util "~3.0.8" + streamifier "~0.1.1" + tar "^2.2.1" + through2 "~2.0.3" + +gulp-util@~3.0.8: + version "3.0.8" + resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f" + dependencies: + array-differ "^1.0.0" + array-uniq "^1.0.2" + beeper "^1.0.0" + chalk "^1.0.0" + dateformat "^2.0.0" + fancy-log "^1.1.0" + gulplog "^1.0.0" + has-gulplog "^0.1.0" + lodash._reescape "^3.0.0" + lodash._reevaluate "^3.0.0" + lodash._reinterpolate "^3.0.0" + lodash.template "^3.0.0" + minimist "^1.1.0" + multipipe "^0.1.2" + object-assign "^3.0.0" + replace-ext "0.0.1" + through2 "^2.0.0" + vinyl "^0.5.0" + +gulp-vinyl-zip@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/gulp-vinyl-zip/-/gulp-vinyl-zip-2.1.0.tgz#24e40685dc05b7149995245099e0590263be8dad" + dependencies: + event-stream "^3.3.1" + queue "^4.2.1" + through2 "^2.0.3" + vinyl "^2.0.2" + vinyl-fs "^2.0.0" + yauzl "^2.2.1" + yazl "^2.2.1" + +gulplog@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5" + dependencies: + glogg "^1.0.0" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + +har-validator@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + dependencies: + chalk "^1.1.1" + commander "^2.9.0" + is-my-json-valid "^2.12.4" + pinkie-promise "^2.0.0" + +har-validator@~5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" + dependencies: + ajv "^5.1.0" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-flag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + +has-gulplog@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce" + dependencies: + sparkles "^1.0.0" + +hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +hawk@~6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-6.0.2.tgz#af4d914eb065f9b5ce4d9d11c1cb2126eecc3038" + dependencies: + boom "4.x.x" + cryptiles "3.x.x" + hoek "4.x.x" + sntp "2.x.x" + +he@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +hoek@4.x.x: + version "4.2.0" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-extglob@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + dependencies: + is-extglob "^2.1.0" + +is-my-json-valid@^2.12.4: + version "2.17.1" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.1.tgz#3da98914a70a22f0a8563ef1511a246c6fc55471" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + +is-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-stream@^1.0.1, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + +is-valid-glob@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-0.3.0.tgz#d4b55c69f51886f9b65c70d6c2622d37e29f48fe" + +is@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/is/-/is-3.2.1.tgz#d0ac2ad55eb7b0bec926a5266f6c662aaa83dca5" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +jade@0.26.3: + version "0.26.3" + resolved "https://registry.yarnpkg.com/jade/-/jade-0.26.3.tgz#8f10d7977d8d79f2f6ff862a81b0513ccb25686c" + dependencies: + commander "0.6.1" + mkdirp "0.3.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsonpointer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +kind-of@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44" + +kind-of@^3.0.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + dependencies: + is-buffer "^1.1.5" + +lazystream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" + dependencies: + readable-stream "^2.0.5" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + +lodash._basetostring@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5" + +lodash._basevalues@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7" + +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + +lodash._reescape@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a" + +lodash._reevaluate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed" + +lodash._reinterpolate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + +lodash._root@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" + +lodash.escape@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698" + dependencies: + lodash._root "^3.0.0" + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + +lodash.isequal@^4.0.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + +lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.restparam@^3.0.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + +lodash.template@^3.0.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f" + dependencies: + lodash._basecopy "^3.0.0" + lodash._basetostring "^3.0.0" + lodash._basevalues "^3.0.0" + lodash._isiterateecall "^3.0.0" + lodash._reinterpolate "^3.0.0" + lodash.escape "^3.0.0" + lodash.keys "^3.0.0" + lodash.restparam "^3.0.0" + lodash.templatesettings "^3.0.0" + +lodash.templatesettings@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5" + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.escape "^3.0.0" + +lru-cache@2: + version "2.7.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + +map-stream@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" + +merge-stream@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" + dependencies: + readable-stream "^2.0.1" + +micromatch@^2.3.7: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +mime-db@~1.30.0: + version "1.30.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" + +mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.7: + version "2.1.17" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" + dependencies: + mime-db "~1.30.0" + +minimatch@0.3: + version "0.3.0" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd" + dependencies: + lru-cache "2" + sigmund "~1.0.0" + +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +mkdirp@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" + +mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +mocha@^2.3.3: + version "2.5.3" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.5.3.tgz#161be5bdeb496771eb9b35745050b622b5aefc58" + dependencies: + commander "2.3.0" + debug "2.2.0" + diff "1.4.0" + escape-string-regexp "1.0.2" + glob "3.2.11" + growl "1.9.2" + jade "0.26.3" + mkdirp "0.5.1" + supports-color "1.2.0" + to-iso-string "0.0.2" + +mocha@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-4.1.0.tgz#7d86cfbcf35cb829e2754c32e17355ec05338794" + dependencies: + browser-stdout "1.3.0" + commander "2.11.0" + debug "3.1.0" + diff "3.3.1" + escape-string-regexp "1.0.5" + glob "7.1.2" + growl "1.10.3" + he "1.1.1" + mkdirp "0.5.1" + supports-color "4.4.0" + +ms@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +multimatch@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-2.1.0.tgz#9c7906a22fb4c02919e2f5f75161b4cdbd4b2a2b" + dependencies: + array-differ "^1.0.0" + array-union "^1.0.1" + arrify "^1.0.0" + minimatch "^3.0.0" + +multipipe@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b" + dependencies: + duplexer2 "0.0.2" + +node.extend@~1.1.2: + version "1.1.6" + resolved "https://registry.yarnpkg.com/node.extend/-/node.extend-1.1.6.tgz#a7b882c82d6c93a4863a5504bd5de8ec86258b96" + dependencies: + is "^3.1.0" + +normalize-path@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +oauth-sign@~0.8.1, oauth-sign@~0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" + +object-assign@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +once@^1.3.0, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +ordered-read-streams@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz#7137e69b3298bb342247a1bbee3881c80e2fd78b" + dependencies: + is-stream "^1.0.1" + readable-stream "^2.0.1" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +pause-stream@0.0.11: + version "0.0.11" + resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" + dependencies: + through "~2.3" + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +plugin-error@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace" + dependencies: + ansi-cyan "^0.1.1" + ansi-red "^0.1.1" + arr-diff "^1.0.1" + arr-union "^2.0.1" + extend-shallow "^1.1.2" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +process-nextick-args@^1.0.6, process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +qs@~6.3.0: + version "6.3.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" + +qs@~6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" + +querystringify@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb" + +queue@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/queue/-/queue-3.1.0.tgz#6c49d01f009e2256788789f2bffac6b8b9990585" + dependencies: + inherits "~2.0.0" + +queue@^4.2.1: + version "4.4.2" + resolved "https://registry.yarnpkg.com/queue/-/queue-4.4.2.tgz#5a9733d9a8b8bd1b36e934bc9c55ab89b28e29c7" + dependencies: + inherits "~2.0.0" + +randomatic@^1.1.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +"readable-stream@>=1.0.33-1 <1.1.0-0": + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.1.5: + version "2.3.3" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + safe-buffer "~5.1.1" + string_decoder "~1.0.3" + util-deprecate "~1.0.1" + +readable-stream@~1.1.9: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +regex-cache@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + dependencies: + is-equal-shallow "^0.1.3" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +replace-ext@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" + +replace-ext@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" + +request@^2.83.0: + version "2.83.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.3" + hawk "~6.0.2" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + stringstream "~0.0.5" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + +request@~2.79.0: + version "2.79.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + qs "~6.3.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + uuid "^3.0.0" + +requires-port@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + +rimraf@2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" + dependencies: + glob "^7.0.5" + +safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + +semver@^5.4.1: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + +sigmund@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +sntp@2.x.x: + version "2.1.0" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" + dependencies: + hoek "4.x.x" + +source-map-support@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.2.tgz#1a6297fd5b2e762b39688c7fc91233b60984f0a5" + dependencies: + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + +sparkles@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3" + +split@0.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" + dependencies: + through "2" + +sshpk@^1.7.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +stat-mode@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/stat-mode/-/stat-mode-0.2.2.tgz#e6c80b623123d7d80cf132ce538f346289072502" + +stream-combiner@~0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" + dependencies: + duplexer "~0.1.1" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + +streamfilter@^1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/streamfilter/-/streamfilter-1.0.7.tgz#ae3e64522aa5a35c061fd17f67620c7653c643c9" + dependencies: + readable-stream "^2.0.2" + +streamifier@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/streamifier/-/streamifier-0.1.1.tgz#97e98d8fa4d105d62a2691d1dc07e820db8dfc4f" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +string_decoder@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" + dependencies: + safe-buffer "~5.1.0" + +stringstream@~0.0.4, stringstream@~0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-bom-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz#e7144398577d51a6bed0fa1994fa05f43fd988ee" + dependencies: + first-chunk-stream "^1.0.0" + strip-bom "^2.0.0" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + +supports-color@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" + +supports-color@4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" + dependencies: + has-flag "^2.0.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +tar@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +through2-filter@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-2.0.0.tgz#60bc55a0dacb76085db1f9dae99ab43f83d622ec" + dependencies: + through2 "~2.0.0" + xtend "~4.0.0" + +through2@^0.6.0, through2@~0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" + dependencies: + readable-stream ">=1.0.33-1 <1.1.0-0" + xtend ">=4.0.0 <4.1.0-0" + +through2@^2.0.0, through2@^2.0.1, through2@^2.0.3, through2@~2.0.0, through2@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" + dependencies: + readable-stream "^2.1.5" + xtend "~4.0.1" + +through@2, through@~2.3, through@~2.3.1: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +time-stamp@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" + +to-absolute-glob@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz#1cdfa472a9ef50c239ee66999b662ca0eb39937f" + dependencies: + extend-shallow "^2.0.1" + +to-iso-string@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1" + +tough-cookie@~2.3.0, tough-cookie@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" + dependencies: + punycode "^1.4.1" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +tunnel-agent@~0.4.1: + version "0.4.3" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +typescript@^2.3.4: + version "2.6.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4" + +unique-stream@^2.0.2: + version "2.2.1" + resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.2.1.tgz#5aa003cfbe94c5ff866c4e7d668bb1c4dbadb369" + dependencies: + json-stable-stringify "^1.0.0" + through2-filter "^2.0.0" + +url-parse@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.2.0.tgz#3a19e8aaa6d023ddd27dcc44cb4fc8f7fec23986" + dependencies: + querystringify "~1.0.0" + requires-port "~1.0.0" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +uuid@^3.0.0, uuid@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" + +vali-date@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/vali-date/-/vali-date-1.0.0.tgz#1b904a59609fb328ef078138420934f6b86709a6" + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vinyl-fs@^2.0.0, vinyl-fs@^2.4.3: + version "2.4.4" + resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-2.4.4.tgz#be6ff3270cb55dfd7d3063640de81f25d7532239" + dependencies: + duplexify "^3.2.0" + glob-stream "^5.3.2" + graceful-fs "^4.0.0" + gulp-sourcemaps "1.6.0" + is-valid-glob "^0.3.0" + lazystream "^1.0.0" + lodash.isequal "^4.0.0" + merge-stream "^1.0.0" + mkdirp "^0.5.0" + object-assign "^4.0.0" + readable-stream "^2.0.4" + strip-bom "^2.0.0" + strip-bom-stream "^1.0.0" + through2 "^2.0.0" + through2-filter "^2.0.0" + vali-date "^1.0.0" + vinyl "^1.0.0" + +vinyl-source-stream@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vinyl-source-stream/-/vinyl-source-stream-1.1.2.tgz#62b53a135610a896e98ca96bee3a87f008a8e780" + dependencies: + through2 "^2.0.3" + vinyl "^0.4.3" + +vinyl@^0.4.3, vinyl@~0.4.6: + version "0.4.6" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.4.6.tgz#2f356c87a550a255461f36bbeb2a5ba8bf784847" + dependencies: + clone "^0.2.0" + clone-stats "^0.0.1" + +vinyl@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde" + dependencies: + clone "^1.0.0" + clone-stats "^0.0.1" + replace-ext "0.0.1" + +vinyl@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" + dependencies: + clone "^1.0.0" + clone-stats "^0.0.1" + replace-ext "0.0.1" + +vinyl@^2.0.2: + version "2.1.0" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.1.0.tgz#021f9c2cf951d6b939943c89eb5ee5add4fd924c" + dependencies: + clone "^2.1.1" + clone-buffer "^1.0.0" + clone-stats "^1.0.0" + cloneable-readable "^1.0.0" + remove-trailing-separator "^1.0.1" + replace-ext "^1.0.0" + +vinyl@~2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.0.2.tgz#0a3713d8d4e9221c58f10ca16c0116c9e25eda7c" + dependencies: + clone "^1.0.0" + clone-buffer "^1.0.0" + clone-stats "^1.0.0" + cloneable-readable "^1.0.0" + is-stream "^1.1.0" + remove-trailing-separator "^1.0.1" + replace-ext "^1.0.0" + +vscode-jsonrpc@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-3.5.0.tgz#87239d9e166b2d7352245b8a813597804c1d63aa" + +vscode-languageclient@^3.4.5: + version "3.5.0" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-3.5.0.tgz#36d02cc186a8365a4467719a290fb200a9ae490a" + dependencies: + vscode-languageserver-protocol "^3.5.0" + +vscode-languageserver-protocol@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.5.0.tgz#067c5cbe27709795398d119692c97ebba1452209" + dependencies: + vscode-jsonrpc "^3.5.0" + vscode-languageserver-types "^3.5.0" + +vscode-languageserver-types@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.5.0.tgz#e48d79962f0b8e02de955e3f524908e2b19c0374" + +vscode@^1.1.4: + version "1.1.10" + resolved "https://registry.yarnpkg.com/vscode/-/vscode-1.1.10.tgz#d1cba378ab24f1d3ddf9cd470d242ee1472dd35b" + dependencies: + glob "^7.1.2" + gulp-chmod "^2.0.0" + gulp-filter "^5.0.1" + gulp-gunzip "1.0.0" + gulp-remote-src "^0.4.3" + gulp-symdest "^1.1.0" + gulp-untar "^0.0.6" + gulp-vinyl-zip "^2.1.0" + mocha "^4.0.1" + request "^2.83.0" + semver "^5.4.1" + source-map-support "^0.5.0" + url-parse "^1.1.9" + vinyl-source-stream "^1.1.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +yauzl@^2.2.1: + version "2.9.1" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.9.1.tgz#a81981ea70a57946133883f029c5821a89359a7f" + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.0.1" + +yazl@^2.2.1: + version "2.4.3" + resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.4.3.tgz#ec26e5cc87d5601b9df8432dbdd3cd2e5173a071" + dependencies: + buffer-crc32 "~0.2.3" From 1c0cf7b1a7a65229ec313c18a1d2eed5b4f77043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Andr=C3=A9s=20Margffoy=20Tuay?= Date: Thu, 28 May 2020 19:21:38 -0500 Subject: [PATCH 05/10] Pin old jedi and parso version and extract dependencies to other file in 2.7 --- .github/scripts/install.sh | 6 +++++- requirements/conda-2.7.txt | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 requirements/conda-2.7.txt diff --git a/.github/scripts/install.sh b/.github/scripts/install.sh index 7f0872ea05e..d3e004baf8b 100755 --- a/.github/scripts/install.sh +++ b/.github/scripts/install.sh @@ -14,7 +14,11 @@ if [ "$USE_CONDA" = "true" ]; then fi # Install main dependencies - conda install python=$PYTHON_VERSION --file requirements/conda.txt -q -y + if [ "$PYTHON_VERSION" = "2.7" ]; then + conda install python=$PYTHON_VERSION --file requirements/conda-2.7.txt -q -y + else + conda install python=$PYTHON_VERSION --file requirements/conda.txt -q -y + fi # Install test ones conda install python=$PYTHON_VERSION --file requirements/tests.txt -c spyder-ide -q -y diff --git a/requirements/conda-2.7.txt b/requirements/conda-2.7.txt new file mode 100644 index 00000000000..6492a8693d6 --- /dev/null +++ b/requirements/conda-2.7.txt @@ -0,0 +1,38 @@ +# We can not refer to an environment.yml file from another +# So to get performant launches on mybinder.org, we have copied +# the contents of this file to binder/environment.yml. If you +# make changes here, please copy them over there too. +applaunchservices >=0.1.7 +atomicwrites >=1.2.0 +chardet >=2.0.0 +cloudpickle >=0.5.0 +diff-match-patch >=20181111 +intervaltree +IPython >=4.0 +jedi =0.15.2 +keyring +nbconvert >=4.0 +numpydoc >=0.6.0 +Paramiko >=2.4.0 +parso =0.5.2 +pexpect >=4.4.0 +pickleshare >=0.4 +psutil >=5.3 +pygments >=2.0 +pylint >=1.0 +pyqt <5.13 +# There's no need to set a version for python-language-server +# because we install it from master for our tests. +python-language-server +pyxdg >=0.26 +pyzmq >=17 +qdarkstyle >=2.8 +qtawesome >=0.5.7 +qtconsole >=4.6.0 +qtpy >=1.5.0 +rtree >=0.8.3 +sphinx >=0.6.6 +# NOTE: There's no need to set a version for spyder-kernels +# here because we're using a subrepo for it to run our tests. +spyder-kernels +watchdog From 82e2b4c3c804a3c304f5feacc14357bae5d10e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Andr=C3=A9s=20Margffoy=20Tuay?= Date: Thu, 28 May 2020 19:24:50 -0500 Subject: [PATCH 06/10] Pin specific versions in dependencies.py --- spyder/dependencies.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spyder/dependencies.py b/spyder/dependencies.py index e43418f26c5..d44a02662ab 100644 --- a/spyder/dependencies.py +++ b/spyder/dependencies.py @@ -36,12 +36,12 @@ DIFF_MATCH_PATCH_REQVER = '>=20181111' INTERVALTREE_REQVER = None IPYTHON_REQVER = ">=4.0;<6.0" if PY2 else ">=4.0" -JEDI_REQVER = '=0.17.0' +JEDI_REQVER = '=0.17.0' if not PY2 else "=0.15.2" KEYRING_REQVER = None NBCONVERT_REQVER = '>=4.0' NUMPYDOC_REQVER = '>=0.6.0' PARAMIKO_REQVER = '>=2.4.0' -PARSO_REQVER = '=0.7.0' +PARSO_REQVER = '=0.7.0' if not PY2 else "=0.5.2" PEXPECT_REQVER = '>=4.4.0' PICKLESHARE_REQVER = '>=0.4' PSUTIL_REQVER = '>=5.3' From f36e902dc44bb4f12435b665faacb9c668d0d46a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Andr=C3=A9s=20Margffoy=20Tuay?= Date: Thu, 28 May 2020 19:43:27 -0500 Subject: [PATCH 07/10] Do not install subrepo on Py2 --- .github/scripts/install.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/scripts/install.sh b/.github/scripts/install.sh index d3e004baf8b..ebd1af30d85 100755 --- a/.github/scripts/install.sh +++ b/.github/scripts/install.sh @@ -49,13 +49,17 @@ else # Remove packages we have subrepos for pip uninstall spyder-kernels -q -y - pip uninstall python-language-server -q -y + if [ "$PYTHON_VERSION" != "2.7" ]; then + pip uninstall python-language-server -q -y + fi fi # Install python-language-server from our subrepo -pushd external-deps/python-language-server -pip install --no-deps -q -e . -popd +if [ "$PYTHON_VERSION" != "2.7" ]; then + pushd external-deps/python-language-server + pip install --no-deps -q -e . + popd +fi # To check our manifest pip install check-manifest From fc1a1a7e244da579091cd8c66007d737b31f3cfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edgar=20Andr=C3=A9s=20Margffoy=20Tuay?= Date: Thu, 28 May 2020 20:07:02 -0500 Subject: [PATCH 08/10] Update pyls version --- setup.py | 2 +- spyder/dependencies.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index 9851f25fc10..870d0c2a67c 100644 --- a/setup.py +++ b/setup.py @@ -226,7 +226,7 @@ def run(self): 'pylint>=1.0', 'pyqt5<5.13;python_version>="3"', 'pyqtwebengine<5.13;python_version>="3"', - 'python-language-server[all]>=0.31.9,<0.32.0', + 'python-language-server[all]>=0.33.0,<0.34.0', 'pyxdg>=0.26;platform_system=="Linux"', 'pyzmq>=17', 'qdarkstyle>=2.8', diff --git a/spyder/dependencies.py b/spyder/dependencies.py index d44a02662ab..275163ccd45 100644 --- a/spyder/dependencies.py +++ b/spyder/dependencies.py @@ -36,18 +36,18 @@ DIFF_MATCH_PATCH_REQVER = '>=20181111' INTERVALTREE_REQVER = None IPYTHON_REQVER = ">=4.0;<6.0" if PY2 else ">=4.0" -JEDI_REQVER = '=0.17.0' if not PY2 else "=0.15.2" +JEDI_REQVER = '=0.17.0' KEYRING_REQVER = None NBCONVERT_REQVER = '>=4.0' NUMPYDOC_REQVER = '>=0.6.0' PARAMIKO_REQVER = '>=2.4.0' -PARSO_REQVER = '=0.7.0' if not PY2 else "=0.5.2" +PARSO_REQVER = '=0.7.0' PEXPECT_REQVER = '>=4.4.0' PICKLESHARE_REQVER = '>=0.4' PSUTIL_REQVER = '>=5.3' PYGMENTS_REQVER = '>=2.0' PYLINT_REQVER = '>=1.0' -PYLS_REQVER = '>=0.31.9;<0.32.0' +PYLS_REQVER = '>=0.33.0;<0.34.0' PYXDG_REQVER = '>=0.26' PYZMQ_REQVER = '>=17' QDARKSTYLE_REQVER = '>=2.8' From 41e70a114c6ae1429116d4e2c803020d83a96707 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Thu, 4 Jun 2020 23:33:30 -0500 Subject: [PATCH 09/10] Testing: Exclude slow tests on Python 2.7 --- .github/workflows/test-linux.yml | 3 +++ .github/workflows/test-mac.yml | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/.github/workflows/test-linux.yml b/.github/workflows/test-linux.yml index fdc10022d79..341ec8a8051 100644 --- a/.github/workflows/test-linux.yml +++ b/.github/workflows/test-linux.yml @@ -53,6 +53,9 @@ jobs: - INSTALL_TYPE: 'pip' PYTHON_VERSION: '2.7' TEST_TYPE: 'slow' + - INSTALL_TYPE: 'conda' + PYTHON_VERSION: '2.7' + TEST_TYPE: 'slow' steps: - name: Checkout Pull Requests if: github.event_name == 'pull_request' diff --git a/.github/workflows/test-mac.yml b/.github/workflows/test-mac.yml index cc0570a0829..c2acd4a9ac1 100644 --- a/.github/workflows/test-mac.yml +++ b/.github/workflows/test-mac.yml @@ -46,6 +46,10 @@ jobs: INSTALL_TYPE: ['conda'] PYTHON_VERSION: ['3.7', '2.7'] TEST_TYPE: ['fast', 'slow'] + exclude: + - INSTALL_TYPE: 'conda' + PYTHON_VERSION: '2.7' + TEST_TYPE: 'slow' steps: - name: Checkout Pull Requests if: github.event_name == 'pull_request' From d09b0eff7cc1ee421c658142ddd9b8d239403352 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Thu, 4 Jun 2020 23:41:26 -0500 Subject: [PATCH 10/10] Ignore external-deps from pep8speaks --- .pep8speaks.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.pep8speaks.yml b/.pep8speaks.yml index 17e3d03e5eb..1fa77a15bf2 100644 --- a/.pep8speaks.yml +++ b/.pep8speaks.yml @@ -1,4 +1,6 @@ -# File : .pep8speaks.yml - scanner: diff_only: True # Errors caused by only the patch are shown + linter: pycodestyle + +pycodestyle: + exclude: external-deps