diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8d0e74e..2a6eb7c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,6 +1,6 @@ name: Tests -on: [push, pull_request] +on: [pull_request] jobs: build: diff --git a/poetry.lock b/poetry.lock index 4d9dcdd..3fd4780 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,59 +1,104 @@ [[package]] +name = "appdirs" +version = "1.4.4" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" -description = "Atomic file writes." -name = "atomicwrites" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.3.0" - -[[package]] -category = "dev" -description = "Classes Without Boilerplate" -name = "attrs" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "19.3.0" - -[[package]] -category = "dev" -description = "Cross-platform colored terminal text." -marker = "sys_platform == \"win32\"" -name = "colorama" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.4.1" - -[[package]] -category = "dev" -description = "Code coverage measurement for Python" -name = "coverage" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -version = "5.0" - -[[package]] -category = "dev" -description = "Discover and load entry points from installed packages." -name = "entrypoints" -optional = false -python-versions = ">=2.7" -version = "0.3" - -[[package]] -category = "dev" -description = "A platform independent file lock." -name = "filelock" optional = false python-versions = "*" -version = "3.0.12" [[package]] +name = "atomicwrites" +version = "1.3.0" +description = "Atomic file writes." category = "dev" -description = "the modular source code checker: pep8, pyflakes and co" -name = "flake8" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "attrs" +version = "19.3.0" +description = "Classes Without Boilerplate" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[package.extras] +azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"] +dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"] +docs = ["sphinx", "zope.interface"] +tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] + +[[package]] +name = "black" +version = "19.10b0" +description = "The uncompromising code formatter." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] + +[package.dependencies] +appdirs = "*" +attrs = ">=18.1.0" +click = ">=6.5" +pathspec = ">=0.6,<1" +regex = "*" +toml = ">=0.9.4" +typed-ast = ">=1.4.0" + +[[package]] +name = "click" +version = "7.1.2" +description = "Composable command line interface toolkit" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "colorama" +version = "0.4.1" +description = "Cross-platform colored terminal text." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +marker = "sys_platform == \"win32\"" + +[[package]] +name = "coverage" +version = "5.0" +description = "Code coverage measurement for Python" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" + +[package.extras] +toml = ["toml"] + +[[package]] +name = "entrypoints" +version = "0.3" +description = "Discover and load entry points from installed packages." +category = "dev" +optional = false +python-versions = ">=2.7" + +[[package]] +name = "filelock" +version = "3.0.12" +description = "A platform independent file lock." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "flake8" version = "3.7.8" +description = "the modular source code checker: pep8, pyflakes and co" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] entrypoints = ">=0.3.0,<0.4.0" @@ -62,48 +107,61 @@ pycodestyle = ">=2.5.0,<2.6.0" pyflakes = ">=2.1.0,<2.2.0" [[package]] -category = "dev" -description = "Read metadata from Python packages" -marker = "python_version < \"3.8\"" name = "importlib-metadata" +version = "0.23" +description = "Read metadata from Python packages" +category = "dev" optional = false python-versions = ">=2.7,!=3.0,!=3.1,!=3.2,!=3.3" -version = "0.23" +marker = "python_version < \"3.8\"" + +[package.extras] +docs = ["sphinx", "rst.linker"] +testing = ["packaging", "importlib-resources"] [package.dependencies] zipp = ">=0.5" [[package]] -category = "dev" -description = "A Python utility / library to sort Python imports." name = "isort" +version = "4.3.21" +description = "A Python utility / library to sort Python imports." +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "4.3.21" + +[package.extras] +pipfile = ["pipreqs", "requirementslib"] +pyproject = ["toml"] +requirements = ["pipreqs", "pip-api"] +xdg_home = ["appdirs (>=1.4.0)"] [[package]] -category = "dev" -description = "McCabe checker, plugin for flake8" name = "mccabe" +version = "0.6.1" +description = "McCabe checker, plugin for flake8" +category = "dev" optional = false python-versions = "*" -version = "0.6.1" [[package]] -category = "dev" -description = "More routines for operating on iterables, beyond itertools" name = "more-itertools" +version = "7.2.0" +description = "More routines for operating on iterables, beyond itertools" +category = "dev" optional = false python-versions = ">=3.4" -version = "7.2.0" [[package]] -category = "dev" -description = "Optional static typing for Python" name = "mypy" +version = "0.740" +description = "Optional static typing for Python" +category = "dev" optional = false python-versions = ">=3.5" -version = "0.740" + +[package.extras] +dmypy = ["psutil (>=4.0)"] [package.dependencies] mypy-extensions = ">=0.4.0,<0.5.0" @@ -111,85 +169,104 @@ typed-ast = ">=1.4.0,<1.5.0" typing-extensions = ">=3.7.4" [[package]] -category = "dev" -description = "Experimental type system extensions for programs checked with the mypy typechecker." name = "mypy-extensions" +version = "0.4.3" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +category = "dev" optional = false python-versions = "*" -version = "0.4.3" [[package]] -category = "dev" -description = "Core utilities for Python packages" name = "packaging" +version = "19.2" +description = "Core utilities for Python packages" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "19.2" [package.dependencies] pyparsing = ">=2.0.2" six = "*" [[package]] +name = "pathspec" +version = "0.8.0" +description = "Utility library for gitignore style pattern matching of file paths." category = "dev" -description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] name = "pluggy" +version = "0.13.0" +description = "plugin and hook calling mechanisms for python" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "0.13.0" + +[package.extras] +dev = ["pre-commit", "tox"] [package.dependencies] [package.dependencies.importlib-metadata] -python = "<3.8" version = ">=0.12" +python = "<3.8" [[package]] -category = "dev" -description = "library with cross-python path, ini-parsing, io, code, log facilities" name = "py" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "1.8.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] -category = "dev" -description = "Python style guide checker" name = "pycodestyle" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "2.5.0" - -[[package]] +description = "Python style guide checker" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pyflakes" +version = "2.1.1" +description = "passive checker of Python programs" category = "dev" -description = "passive checker of Python programs" -name = "pyflakes" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.1.1" [[package]] -category = "main" -description = "a pythonic generic language server (pronounced like \"pie glass\")." name = "pygls" +version = "0.8.1" +description = "a pythonic generic language server (pronounced like \"pie glass\")." +category = "main" optional = false python-versions = "*" -version = "0.8.1" + +[package.extras] +dev = ["bandit (1.6.0)", "flake8 (3.7.7)"] +docs = ["sphinx (2.0.1)", "sphinx-rtd-theme (0.4.3)"] +test = ["mock (3.0.5)", "pytest (4.5.0)", "pytest-asyncio (0.10.0)"] [[package]] -category = "main" -description = "Python parsing module" name = "pyparsing" +version = "2.4.2" +description = "Python parsing module" +category = "main" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" -version = "2.4.2" [[package]] -category = "dev" -description = "pytest: simple powerful testing with Python" name = "pytest" +version = "5.2.1" +description = "pytest: simple powerful testing with Python" +category = "dev" optional = false python-versions = ">=3.5" -version = "5.2.1" + +[package.extras] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] [package.dependencies] atomicwrites = ">=1.0" @@ -202,55 +279,70 @@ py = ">=1.5.0" wcwidth = "*" [package.dependencies.importlib-metadata] -python = "<3.8" version = ">=0.12" +python = "<3.8" [[package]] -category = "dev" -description = "Pytest plugin for measuring coverage." name = "pytest-cov" +version = "2.8.1" +description = "Pytest plugin for measuring coverage." +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "2.8.1" + +[package.extras] +testing = ["fields", "hunter", "process-tests (2.0.2)", "six", "virtualenv"] [package.dependencies] coverage = ">=4.4" pytest = ">=3.6" [[package]] -category = "dev" -description = "pytest plugin for test data directories and files" name = "pytest-datadir" +version = "1.3.1" +description = "pytest plugin for test data directories and files" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "1.3.1" [package.dependencies] pytest = ">=2.7.0" [[package]] +name = "regex" +version = "2020.7.14" +description = "Alternative regular expression module, to replace re." category = "dev" -description = "Python 2 and 3 compatibility utilities" -name = "six" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*" -version = "1.12.0" - -[[package]] -category = "dev" -description = "Python Library for Tom's Obvious, Minimal Language" -name = "toml" optional = false python-versions = "*" -version = "0.10.0" [[package]] +name = "six" +version = "1.12.0" +description = "Python 2 and 3 compatibility utilities" category = "dev" -description = "tox is a generic virtualenv management and test command line tool" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*" + +[[package]] +name = "toml" +version = "0.10.0" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" +optional = false +python-versions = "*" + +[[package]] name = "tox" +version = "3.14.0" +description = "tox is a generic virtualenv management and test command line tool" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "3.14.0" + +[package.extras] +docs = ["sphinx (>=2.0.0,<3)", "towncrier (>=18.5.0)", "pygments-github-lexers (>=0.0.5)", "sphinxcontrib-autoprogram (>=0.1.5)"] +testing = ["freezegun (>=0.3.11,<1)", "pathlib2 (>=2.3.3,<3)", "pytest (>=4.0.0,<6)", "pytest-cov (>=2.5.1,<3)", "pytest-mock (>=1.10.0,<2)", "pytest-xdist (>=1.22.2,<2)", "pytest-randomly (>=1.2.3,<2)", "flaky (>=3.4.0,<4)", "psutil (>=5.6.1,<6)"] [package.dependencies] filelock = ">=3.0.0,<4" @@ -262,107 +354,304 @@ toml = ">=0.9.4" virtualenv = ">=14.0.0" [package.dependencies.importlib-metadata] -python = "<3.8" version = ">=0.12,<1" +python = "<3.8" [[package]] -category = "dev" -description = "a fork of Python 2 and 3 ast modules with type comment support" name = "typed-ast" -optional = false -python-versions = "*" version = "1.4.0" +description = "a fork of Python 2 and 3 ast modules with type comment support" +category = "dev" +optional = false +python-versions = "*" [[package]] -category = "dev" -description = "Type Hints for Python" name = "typing" +version = "3.7.4.1" +description = "Type Hints for Python" +category = "dev" optional = false python-versions = "*" -version = "3.7.4.1" [[package]] -category = "dev" -description = "Backported and Experimental Type Hints for Python 3.5+" name = "typing-extensions" +version = "3.7.4" +description = "Backported and Experimental Type Hints for Python 3.5+" +category = "dev" optional = false python-versions = "*" -version = "3.7.4" [package.dependencies] typing = ">=3.7.4" [[package]] -category = "dev" -description = "Virtual Python Environment builder" name = "virtualenv" +version = "16.7.7" +description = "Virtual Python Environment builder" +category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" -version = "16.7.7" + +[package.extras] +docs = ["sphinx (>=1.8.0,<2)", "towncrier (>=18.5.0)", "sphinx-rtd-theme (>=0.4.2,<1)"] +testing = ["pytest (>=4.0.0,<5)", "coverage (>=4.5.0,<5)", "pytest-timeout (>=1.3.0,<2)", "six (>=1.10.0,<2)", "pytest-xdist", "pytest-localserver", "pypiserver", "mock", "xonsh"] [[package]] -category = "dev" -description = "Measures number of Terminal column cells of wide-character codes" name = "wcwidth" -optional = false -python-versions = "*" version = "0.1.7" - -[[package]] +description = "Measures number of Terminal column cells of wide-character codes" category = "dev" -description = "A formatter for Python code." -name = "yapf" optional = false python-versions = "*" -version = "0.28.0" [[package]] -category = "dev" -description = "Backport of pathlib-compatible object wrapper for zip files" -marker = "python_version < \"3.8\"" name = "zipp" +version = "0.6.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "dev" optional = false python-versions = ">=2.7" -version = "0.6.0" +marker = "python_version < \"3.8\"" + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] +testing = ["pathlib2", "contextlib2", "unittest2"] [package.dependencies] more-itertools = "*" [metadata] -content-hash = "284b539e6199a16441b6196fcbc38a374c886e328ae0c5e8bf07d0aaa47b0670" +lock-version = "1.0" python-versions = "^3.6" +content-hash = "2a838d1a4c2f23e2510f2a83e999f268cddf10788031e911324496d6af70a1cc" -[metadata.hashes] -atomicwrites = ["03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", "75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"] -attrs = ["08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", "f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"] -colorama = ["05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", "f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"] -coverage = ["0cd13a6e98c37b510a2d34c8281d5e1a226aaf9b65b7d770ef03c63169965351", "1a4b6b6a2a3a6612e6361130c2cc3dc4378d8c221752b96167ccbad94b47f3cd", "2ee55e6dba516ddf6f484aa83ccabbb0adf45a18892204c23486938d12258cde", "3be5338a2eb4ef03c57f20917e1d12a1fd10e3853fed060b6d6b677cb3745898", "44b783b02db03c4777d8cf71bae19eadc171a6f2a96777d916b2c30a1eb3d070", "475bf7c4252af0a56e1abba9606f1e54127cdf122063095c75ab04f6f99cf45e", "47c81ee687eafc2f1db7f03fbe99aab81330565ebc62fb3b61edfc2216a550c8", "4a7f8e72b18f2aca288ff02255ce32cc830bc04d993efbc87abf6beddc9e56c0", "50197163a22fd17f79086e087a787883b3ec9280a509807daf158dfc2a7ded02", "56b13000acf891f700f5067512b804d1ec8c301d627486c678b903859d07f798", "79388ae29c896299b3567965dbcd93255f175c17c6c7bca38614d12718c47466", "79fd5d3d62238c4f583b75d48d53cdae759fe04d4fb18fe8b371d88ad2b6f8be", "7fe3e2fde2bf1d7ce25ebcd2d3de3650b8d60d9a73ce6dcef36e20191291613d", "81042a24f67b96e4287774014fa27220d8a4d91af1043389e4d73892efc89ac6", "81326f1095c53111f8afc95da281e1414185f4a538609a77ca50bdfa39a6c207", "8873dc0d8f42142ea9f20c27bbdc485190fff93823c6795be661703369e5877d", "88d2cbcb0a112f47eef71eb95460b6995da18e6f8ca50c264585abc2c473154b", "91f2491aeab9599956c45a77c5666d323efdec790bfe23fcceafcd91105d585a", "979daa8655ae5a51e8e7a24e7d34e250ae8309fd9719490df92cbb2fe2b0422b", "9c871b006c878a890c6e44a5b2f3c6291335324b298c904dc0402ee92ee1f0be", "a6d092545e5af53e960465f652e00efbf5357adad177b2630d63978d85e46a72", "b5ed7837b923d1d71c4f587ae1539ccd96bfd6be9788f507dbe94dab5febbb5d", "ba259f68250f16d2444cbbfaddaa0bb20e1560a4fdaad50bece25c199e6af864", "be1d89614c6b6c36d7578496dc8625123bda2ff44f224cf8b1c45b810ee7383f", "c1b030a79749aa8d1f1486885040114ee56933b15ccfc90049ba266e4aa2139f", "c95bb147fab76f2ecde332d972d8f4138b8f2daee6c466af4ff3b4f29bd4c19e", "d52c1c2d7e856cecc05aa0526453cb14574f821b7f413cc279b9514750d795c1", "d609a6d564ad3d327e9509846c2c47f170456344521462b469e5cb39e48ba31c", "e1bad043c12fb58e8c7d92b3d7f2f49977dcb80a08a6d1e7a5114a11bf819fca", "e5a675f6829c53c87d79117a8eb656cc4a5f8918185a32fc93ba09778e90f6db", "fec32646b98baf4a22fdceb08703965bd16dea09051fbeb31a04b5b6e72b846c"] -entrypoints = ["589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", "c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"] -filelock = ["18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59", "929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"] -flake8 = ["19241c1cbc971b9962473e4438a2ca19749a7dd002dd1a946eaba171b4114548", "8e9dfa3cecb2400b3738a42c54c3043e821682b9c840b0448c0503f781130696"] -importlib-metadata = ["aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26", "d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af"] -isort = ["54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1", "6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"] -mccabe = ["ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", "dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"] -more-itertools = ["409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832", "92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4"] -mypy = ["1521c186a3d200c399bd5573c828ea2db1362af7209b2adb1bb8532cea2fb36f", "31a046ab040a84a0fc38bc93694876398e62bc9f35eca8ccbf6418b7297f4c00", "3b1a411909c84b2ae9b8283b58b48541654b918e8513c20a400bb946aa9111ae", "48c8bc99380575deb39f5d3400ebb6a8a1cb5cc669bbba4d3bb30f904e0a0e7d", "540c9caa57a22d0d5d3c69047cc9dd0094d49782603eb03069821b41f9e970e9", "672e418425d957e276c291930a3921b4a6413204f53fe7c37cad7bc57b9a3391", "6ed3b9b3fdc7193ea7aca6f3c20549b377a56f28769783a8f27191903a54170f", "9371290aa2cad5ad133e4cdc43892778efd13293406f7340b9ffe99d5ec7c1d9", "ace6ac1d0f87d4072f05b5468a084a45b4eda970e4d26704f201e06d47ab2990", "b428f883d2b3fe1d052c630642cc6afddd07d5cd7873da948644508be3b9d4a7", "d5bf0e6ec8ba346a2cf35cb55bf4adfddbc6b6576fcc9e10863daa523e418dbb", "d7574e283f83c08501607586b3167728c58e8442947e027d2d4c7dcd6d82f453", "dc889c84241a857c263a2b1cd1121507db7d5b5f5e87e77147097230f374d10b", "f4748697b349f373002656bf32fede706a0e713d67bfdcf04edf39b1f61d46eb"] -mypy-extensions = ["090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", "2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"] -packaging = ["28b924174df7a2fa32c1953825ff29c61e2f5e082343165438812f00d3a7fc47", "d9551545c6d761f3def1677baf08ab2a3ca17c56879e70fecba2fc4dde4ed108"] -pluggy = ["0db4b7601aae1d35b4a033282da476845aa19185c1e6964b25cf324b5e4ec3e6", "fa5fa1622fa6dd5c030e9cad086fa19ef6a0cf6d7a2d12318e10cb49d6d68f34"] -py = ["64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", "dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"] -pycodestyle = ["95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", "e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"] -pyflakes = ["17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0", "d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"] -pygls = ["3ee878a828b7bc0873a2ea44208d6846a91aa7dbbbdc052e7fe8cc689f6644fa", "780fd0c5ae95ad02ecaf70b071e43ff8ced8384b7d6bed19311a7b431d26fb88"] -pyparsing = ["6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", "d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4"] -pytest = ["7e4800063ccfc306a53c461442526c5571e1462f61583506ce97e4da6a1d88c8", "ca563435f4941d0cb34767301c27bc65c510cb82e90b9ecf9cb52dc2c63caaa0"] -pytest-cov = ["cc6742d8bac45070217169f5f72ceee1e0e55b0221f54bcf24845972d3a47f2b", "cdbdef4f870408ebdbfeb44e63e07eb18bb4619fae852f6e760645fa36172626"] -pytest-datadir = ["1847ed0efe0bc54cac40ab3fba6d651c2f03d18dd01f2a582979604d32e7621e", "d3af1e738df87515ee509d6135780f25a15959766d9c2b2dbe02bf4fb979cb18"] -six = ["3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"] -toml = ["229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", "235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", "f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"] -tox = ["0bc216b6a2e6afe764476b4a07edf2c1dab99ed82bb146a1130b2e828f5bff5e", "c4f6b319c20ba4913dbfe71ebfd14ff95d1853c4231493608182f66e566ecfe1"] -typed-ast = ["1170afa46a3799e18b4c977777ce137bb53c7485379d9706af8a59f2ea1aa161", "18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", "262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", "2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", "354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", "48e5b1e71f25cfdef98b013263a88d7145879fbb2d5185f2a0c79fa7ebbeae47", "4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", "630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", "66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", "71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", "7954560051331d003b4e2b3eb822d9dd2e376fa4f6d98fee32f452f52dd6ebb2", "838997f4310012cf2e1ad3803bce2f3402e9ffb71ded61b5ee22617b3a7f6b6e", "95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", "bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", "cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", "d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", "d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", "d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", "fdc1c9bbf79510b76408840e009ed65958feba92a88833cdceecff93ae8fff66", "ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12"] -typing = ["91dfe6f3f706ee8cc32d38edbbf304e9b7583fb37108fef38229617f8b3eba23", "c8cabb5ab8945cd2f54917be357d134db9cc1eb039e59d1606dc1e60cb1d9d36", "f38d83c5a7a7086543a0f649564d661859c5146a85775ab90c0d2f93ffaa9714"] -typing-extensions = ["2ed632b30bb54fc3941c382decfd0ee4148f5c591651c9272473fea2c6397d95", "b1edbbf0652660e32ae780ac9433f4231e7339c7f9a8057d0f042fcbcea49b87", "d8179012ec2c620d3791ca6fe2bf7979d979acdbef1fca0bc56b37411db682ed"] -virtualenv = ["11cb4608930d5fd3afb545ecf8db83fa50e1f96fc4fca80c94b07d2c83146589", "d257bb3773e48cac60e475a19b608996c73f4d333b3ba2e4e57d5ac6134e0136"] -wcwidth = ["3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", "f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"] -yapf = ["02ace10a00fa2e36c7ebd1df2ead91dbfbd7989686dc4ccbdc549e95d19f5780", "6f94b6a176a7c114cfa6bad86d40f259bbe0f10cf2fa7f2f4b3596fc5802a41b"] -zipp = ["3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", "f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335"] +[metadata.files] +appdirs = [ + {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, + {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, +] +atomicwrites = [ + {file = "atomicwrites-1.3.0-py2.py3-none-any.whl", hash = "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4"}, + {file = "atomicwrites-1.3.0.tar.gz", hash = "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"}, +] +attrs = [ + {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"}, + {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"}, +] +black = [ + {file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"}, + {file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"}, +] +click = [ + {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, + {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, +] +colorama = [ + {file = "colorama-0.4.1-py2.py3-none-any.whl", hash = "sha256:f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"}, + {file = "colorama-0.4.1.tar.gz", hash = "sha256:05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d"}, +] +coverage = [ + {file = "coverage-5.0-cp27-cp27m-macosx_10_12_x86_64.whl", hash = "sha256:9c871b006c878a890c6e44a5b2f3c6291335324b298c904dc0402ee92ee1f0be"}, + {file = "coverage-5.0-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:e5a675f6829c53c87d79117a8eb656cc4a5f8918185a32fc93ba09778e90f6db"}, + {file = "coverage-5.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:81326f1095c53111f8afc95da281e1414185f4a538609a77ca50bdfa39a6c207"}, + {file = "coverage-5.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:8873dc0d8f42142ea9f20c27bbdc485190fff93823c6795be661703369e5877d"}, + {file = "coverage-5.0-cp27-cp27m-win32.whl", hash = "sha256:44b783b02db03c4777d8cf71bae19eadc171a6f2a96777d916b2c30a1eb3d070"}, + {file = "coverage-5.0-cp27-cp27m-win_amd64.whl", hash = "sha256:d52c1c2d7e856cecc05aa0526453cb14574f821b7f413cc279b9514750d795c1"}, + {file = "coverage-5.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ba259f68250f16d2444cbbfaddaa0bb20e1560a4fdaad50bece25c199e6af864"}, + {file = "coverage-5.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:475bf7c4252af0a56e1abba9606f1e54127cdf122063095c75ab04f6f99cf45e"}, + {file = "coverage-5.0-cp35-cp35m-macosx_10_12_x86_64.whl", hash = "sha256:91f2491aeab9599956c45a77c5666d323efdec790bfe23fcceafcd91105d585a"}, + {file = "coverage-5.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:979daa8655ae5a51e8e7a24e7d34e250ae8309fd9719490df92cbb2fe2b0422b"}, + {file = "coverage-5.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1a4b6b6a2a3a6612e6361130c2cc3dc4378d8c221752b96167ccbad94b47f3cd"}, + {file = "coverage-5.0-cp35-cp35m-win32.whl", hash = "sha256:56b13000acf891f700f5067512b804d1ec8c301d627486c678b903859d07f798"}, + {file = "coverage-5.0-cp35-cp35m-win_amd64.whl", hash = "sha256:81042a24f67b96e4287774014fa27220d8a4d91af1043389e4d73892efc89ac6"}, + {file = "coverage-5.0-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:fec32646b98baf4a22fdceb08703965bd16dea09051fbeb31a04b5b6e72b846c"}, + {file = "coverage-5.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:7fe3e2fde2bf1d7ce25ebcd2d3de3650b8d60d9a73ce6dcef36e20191291613d"}, + {file = "coverage-5.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:be1d89614c6b6c36d7578496dc8625123bda2ff44f224cf8b1c45b810ee7383f"}, + {file = "coverage-5.0-cp36-cp36m-win32.whl", hash = "sha256:47c81ee687eafc2f1db7f03fbe99aab81330565ebc62fb3b61edfc2216a550c8"}, + {file = "coverage-5.0-cp36-cp36m-win_amd64.whl", hash = "sha256:3be5338a2eb4ef03c57f20917e1d12a1fd10e3853fed060b6d6b677cb3745898"}, + {file = "coverage-5.0-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:79388ae29c896299b3567965dbcd93255f175c17c6c7bca38614d12718c47466"}, + {file = "coverage-5.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:4a7f8e72b18f2aca288ff02255ce32cc830bc04d993efbc87abf6beddc9e56c0"}, + {file = "coverage-5.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d609a6d564ad3d327e9509846c2c47f170456344521462b469e5cb39e48ba31c"}, + {file = "coverage-5.0-cp37-cp37m-win32.whl", hash = "sha256:50197163a22fd17f79086e087a787883b3ec9280a509807daf158dfc2a7ded02"}, + {file = "coverage-5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:b5ed7837b923d1d71c4f587ae1539ccd96bfd6be9788f507dbe94dab5febbb5d"}, + {file = "coverage-5.0-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c95bb147fab76f2ecde332d972d8f4138b8f2daee6c466af4ff3b4f29bd4c19e"}, + {file = "coverage-5.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:0cd13a6e98c37b510a2d34c8281d5e1a226aaf9b65b7d770ef03c63169965351"}, + {file = "coverage-5.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:88d2cbcb0a112f47eef71eb95460b6995da18e6f8ca50c264585abc2c473154b"}, + {file = "coverage-5.0-cp38-cp38m-win32.whl", hash = "sha256:2ee55e6dba516ddf6f484aa83ccabbb0adf45a18892204c23486938d12258cde"}, + {file = "coverage-5.0-cp38-cp38m-win_amd64.whl", hash = "sha256:a6d092545e5af53e960465f652e00efbf5357adad177b2630d63978d85e46a72"}, + {file = "coverage-5.0-cp39-cp39m-win32.whl", hash = "sha256:79fd5d3d62238c4f583b75d48d53cdae759fe04d4fb18fe8b371d88ad2b6f8be"}, + {file = "coverage-5.0-cp39-cp39m-win_amd64.whl", hash = "sha256:c1b030a79749aa8d1f1486885040114ee56933b15ccfc90049ba266e4aa2139f"}, + {file = "coverage-5.0.tar.gz", hash = "sha256:e1bad043c12fb58e8c7d92b3d7f2f49977dcb80a08a6d1e7a5114a11bf819fca"}, +] +entrypoints = [ + {file = "entrypoints-0.3-py2.py3-none-any.whl", hash = "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19"}, + {file = "entrypoints-0.3.tar.gz", hash = "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"}, +] +filelock = [ + {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, + {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, +] +flake8 = [ + {file = "flake8-3.7.8-py2.py3-none-any.whl", hash = "sha256:8e9dfa3cecb2400b3738a42c54c3043e821682b9c840b0448c0503f781130696"}, + {file = "flake8-3.7.8.tar.gz", hash = "sha256:19241c1cbc971b9962473e4438a2ca19749a7dd002dd1a946eaba171b4114548"}, +] +importlib-metadata = [ + {file = "importlib_metadata-0.23-py2.py3-none-any.whl", hash = "sha256:d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af"}, + {file = "importlib_metadata-0.23.tar.gz", hash = "sha256:aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26"}, +] +isort = [ + {file = "isort-4.3.21-py2.py3-none-any.whl", hash = "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"}, + {file = "isort-4.3.21.tar.gz", hash = "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1"}, +] +mccabe = [ + {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, + {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, +] +more-itertools = [ + {file = "more-itertools-7.2.0.tar.gz", hash = "sha256:409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832"}, + {file = "more_itertools-7.2.0-py3-none-any.whl", hash = "sha256:92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4"}, +] +mypy = [ + {file = "mypy-0.740-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:9371290aa2cad5ad133e4cdc43892778efd13293406f7340b9ffe99d5ec7c1d9"}, + {file = "mypy-0.740-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b428f883d2b3fe1d052c630642cc6afddd07d5cd7873da948644508be3b9d4a7"}, + {file = "mypy-0.740-cp35-cp35m-win_amd64.whl", hash = "sha256:ace6ac1d0f87d4072f05b5468a084a45b4eda970e4d26704f201e06d47ab2990"}, + {file = "mypy-0.740-cp36-cp36m-macosx_10_6_x86_64.whl", hash = "sha256:d7574e283f83c08501607586b3167728c58e8442947e027d2d4c7dcd6d82f453"}, + {file = "mypy-0.740-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d5bf0e6ec8ba346a2cf35cb55bf4adfddbc6b6576fcc9e10863daa523e418dbb"}, + {file = "mypy-0.740-cp36-cp36m-win_amd64.whl", hash = "sha256:1521c186a3d200c399bd5573c828ea2db1362af7209b2adb1bb8532cea2fb36f"}, + {file = "mypy-0.740-cp37-cp37m-macosx_10_6_x86_64.whl", hash = "sha256:dc889c84241a857c263a2b1cd1121507db7d5b5f5e87e77147097230f374d10b"}, + {file = "mypy-0.740-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6ed3b9b3fdc7193ea7aca6f3c20549b377a56f28769783a8f27191903a54170f"}, + {file = "mypy-0.740-cp37-cp37m-win_amd64.whl", hash = "sha256:31a046ab040a84a0fc38bc93694876398e62bc9f35eca8ccbf6418b7297f4c00"}, + {file = "mypy-0.740-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:672e418425d957e276c291930a3921b4a6413204f53fe7c37cad7bc57b9a3391"}, + {file = "mypy-0.740-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3b1a411909c84b2ae9b8283b58b48541654b918e8513c20a400bb946aa9111ae"}, + {file = "mypy-0.740-cp38-cp38-win_amd64.whl", hash = "sha256:540c9caa57a22d0d5d3c69047cc9dd0094d49782603eb03069821b41f9e970e9"}, + {file = "mypy-0.740-py3-none-any.whl", hash = "sha256:f4748697b349f373002656bf32fede706a0e713d67bfdcf04edf39b1f61d46eb"}, + {file = "mypy-0.740.tar.gz", hash = "sha256:48c8bc99380575deb39f5d3400ebb6a8a1cb5cc669bbba4d3bb30f904e0a0e7d"}, +] +mypy-extensions = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, +] +packaging = [ + {file = "packaging-19.2-py2.py3-none-any.whl", hash = "sha256:d9551545c6d761f3def1677baf08ab2a3ca17c56879e70fecba2fc4dde4ed108"}, + {file = "packaging-19.2.tar.gz", hash = "sha256:28b924174df7a2fa32c1953825ff29c61e2f5e082343165438812f00d3a7fc47"}, +] +pathspec = [ + {file = "pathspec-0.8.0-py2.py3-none-any.whl", hash = "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0"}, + {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"}, +] +pluggy = [ + {file = "pluggy-0.13.0-py2.py3-none-any.whl", hash = "sha256:0db4b7601aae1d35b4a033282da476845aa19185c1e6964b25cf324b5e4ec3e6"}, + {file = "pluggy-0.13.0.tar.gz", hash = "sha256:fa5fa1622fa6dd5c030e9cad086fa19ef6a0cf6d7a2d12318e10cb49d6d68f34"}, +] +py = [ + {file = "py-1.8.0-py2.py3-none-any.whl", hash = "sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa"}, + {file = "py-1.8.0.tar.gz", hash = "sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"}, +] +pycodestyle = [ + {file = "pycodestyle-2.5.0-py2.py3-none-any.whl", hash = "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56"}, + {file = "pycodestyle-2.5.0.tar.gz", hash = "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"}, +] +pyflakes = [ + {file = "pyflakes-2.1.1-py2.py3-none-any.whl", hash = "sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0"}, + {file = "pyflakes-2.1.1.tar.gz", hash = "sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"}, +] +pygls = [ + {file = "pygls-0.8.1-py3-none-any.whl", hash = "sha256:3ee878a828b7bc0873a2ea44208d6846a91aa7dbbbdc052e7fe8cc689f6644fa"}, + {file = "pygls-0.8.1.tar.gz", hash = "sha256:780fd0c5ae95ad02ecaf70b071e43ff8ced8384b7d6bed19311a7b431d26fb88"}, +] +pyparsing = [ + {file = "pyparsing-2.4.2-py2.py3-none-any.whl", hash = "sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4"}, + {file = "pyparsing-2.4.2.tar.gz", hash = "sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80"}, +] +pytest = [ + {file = "pytest-5.2.1-py3-none-any.whl", hash = "sha256:7e4800063ccfc306a53c461442526c5571e1462f61583506ce97e4da6a1d88c8"}, + {file = "pytest-5.2.1.tar.gz", hash = "sha256:ca563435f4941d0cb34767301c27bc65c510cb82e90b9ecf9cb52dc2c63caaa0"}, +] +pytest-cov = [ + {file = "pytest-cov-2.8.1.tar.gz", hash = "sha256:cc6742d8bac45070217169f5f72ceee1e0e55b0221f54bcf24845972d3a47f2b"}, + {file = "pytest_cov-2.8.1-py2.py3-none-any.whl", hash = "sha256:cdbdef4f870408ebdbfeb44e63e07eb18bb4619fae852f6e760645fa36172626"}, +] +pytest-datadir = [ + {file = "pytest-datadir-1.3.1.tar.gz", hash = "sha256:d3af1e738df87515ee509d6135780f25a15959766d9c2b2dbe02bf4fb979cb18"}, + {file = "pytest_datadir-1.3.1-py2.py3-none-any.whl", hash = "sha256:1847ed0efe0bc54cac40ab3fba6d651c2f03d18dd01f2a582979604d32e7621e"}, +] +regex = [ + {file = "regex-2020.7.14-cp27-cp27m-win32.whl", hash = "sha256:e46d13f38cfcbb79bfdb2964b0fe12561fe633caf964a77a5f8d4e45fe5d2ef7"}, + {file = "regex-2020.7.14-cp27-cp27m-win_amd64.whl", hash = "sha256:6961548bba529cac7c07af2fd4d527c5b91bb8fe18995fed6044ac22b3d14644"}, + {file = "regex-2020.7.14-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:c50a724d136ec10d920661f1442e4a8b010a4fe5aebd65e0c2241ea41dbe93dc"}, + {file = "regex-2020.7.14-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8a51f2c6d1f884e98846a0a9021ff6861bdb98457879f412fdc2b42d14494067"}, + {file = "regex-2020.7.14-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:9c568495e35599625f7b999774e29e8d6b01a6fb684d77dee1f56d41b11b40cd"}, + {file = "regex-2020.7.14-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:51178c738d559a2d1071ce0b0f56e57eb315bcf8f7d4cf127674b533e3101f88"}, + {file = "regex-2020.7.14-cp36-cp36m-win32.whl", hash = "sha256:9eddaafb3c48e0900690c1727fba226c4804b8e6127ea409689c3bb492d06de4"}, + {file = "regex-2020.7.14-cp36-cp36m-win_amd64.whl", hash = "sha256:14a53646369157baa0499513f96091eb70382eb50b2c82393d17d7ec81b7b85f"}, + {file = "regex-2020.7.14-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:1269fef3167bb52631ad4fa7dd27bf635d5a0790b8e6222065d42e91bede4162"}, + {file = "regex-2020.7.14-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d0a5095d52b90ff38592bbdc2644f17c6d495762edf47d876049cfd2968fbccf"}, + {file = "regex-2020.7.14-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:4c037fd14c5f4e308b8370b447b469ca10e69427966527edcab07f52d88388f7"}, + {file = "regex-2020.7.14-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bc3d98f621898b4a9bc7fecc00513eec8f40b5b83913d74ccb445f037d58cd89"}, + {file = "regex-2020.7.14-cp37-cp37m-win32.whl", hash = "sha256:46bac5ca10fb748d6c55843a931855e2727a7a22584f302dd9bb1506e69f83f6"}, + {file = "regex-2020.7.14-cp37-cp37m-win_amd64.whl", hash = "sha256:0dc64ee3f33cd7899f79a8d788abfbec168410be356ed9bd30bbd3f0a23a7204"}, + {file = "regex-2020.7.14-cp38-cp38-manylinux1_i686.whl", hash = "sha256:5ea81ea3dbd6767873c611687141ec7b06ed8bab43f68fad5b7be184a920dc99"}, + {file = "regex-2020.7.14-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:bbb332d45b32df41200380fff14712cb6093b61bd142272a10b16778c418e98e"}, + {file = "regex-2020.7.14-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:c11d6033115dc4887c456565303f540c44197f4fc1a2bfb192224a301534888e"}, + {file = "regex-2020.7.14-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:75aaa27aa521a182824d89e5ab0a1d16ca207318a6b65042b046053cfc8ed07a"}, + {file = "regex-2020.7.14-cp38-cp38-win32.whl", hash = "sha256:d6cff2276e502b86a25fd10c2a96973fdb45c7a977dca2138d661417f3728341"}, + {file = "regex-2020.7.14-cp38-cp38-win_amd64.whl", hash = "sha256:7a2dd66d2d4df34fa82c9dc85657c5e019b87932019947faece7983f2089a840"}, + {file = "regex-2020.7.14.tar.gz", hash = "sha256:3a3af27a8d23143c49a3420efe5b3f8cf1a48c6fc8bc6856b03f638abc1833bb"}, +] +six = [ + {file = "six-1.12.0-py2.py3-none-any.whl", hash = "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c"}, + {file = "six-1.12.0.tar.gz", hash = "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"}, +] +toml = [ + {file = "toml-0.10.0-py2.7.egg", hash = "sha256:f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"}, + {file = "toml-0.10.0-py2.py3-none-any.whl", hash = "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"}, + {file = "toml-0.10.0.tar.gz", hash = "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c"}, +] +tox = [ + {file = "tox-3.14.0-py2.py3-none-any.whl", hash = "sha256:0bc216b6a2e6afe764476b4a07edf2c1dab99ed82bb146a1130b2e828f5bff5e"}, + {file = "tox-3.14.0.tar.gz", hash = "sha256:c4f6b319c20ba4913dbfe71ebfd14ff95d1853c4231493608182f66e566ecfe1"}, +] +typed-ast = [ + {file = "typed_ast-1.4.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e"}, + {file = "typed_ast-1.4.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b"}, + {file = "typed_ast-1.4.0-cp35-cp35m-win32.whl", hash = "sha256:630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4"}, + {file = "typed_ast-1.4.0-cp35-cp35m-win_amd64.whl", hash = "sha256:ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12"}, + {file = "typed_ast-1.4.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631"}, + {file = "typed_ast-1.4.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233"}, + {file = "typed_ast-1.4.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1"}, + {file = "typed_ast-1.4.0-cp36-cp36m-win32.whl", hash = "sha256:d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a"}, + {file = "typed_ast-1.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c"}, + {file = "typed_ast-1.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a"}, + {file = "typed_ast-1.4.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e"}, + {file = "typed_ast-1.4.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d"}, + {file = "typed_ast-1.4.0-cp37-cp37m-win32.whl", hash = "sha256:d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36"}, + {file = "typed_ast-1.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0"}, + {file = "typed_ast-1.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fdc1c9bbf79510b76408840e009ed65958feba92a88833cdceecff93ae8fff66"}, + {file = "typed_ast-1.4.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:7954560051331d003b4e2b3eb822d9dd2e376fa4f6d98fee32f452f52dd6ebb2"}, + {file = "typed_ast-1.4.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:48e5b1e71f25cfdef98b013263a88d7145879fbb2d5185f2a0c79fa7ebbeae47"}, + {file = "typed_ast-1.4.0-cp38-cp38-win32.whl", hash = "sha256:1170afa46a3799e18b4c977777ce137bb53c7485379d9706af8a59f2ea1aa161"}, + {file = "typed_ast-1.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:838997f4310012cf2e1ad3803bce2f3402e9ffb71ded61b5ee22617b3a7f6b6e"}, + {file = "typed_ast-1.4.0.tar.gz", hash = "sha256:66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34"}, +] +typing = [ + {file = "typing-3.7.4.1-py2-none-any.whl", hash = "sha256:c8cabb5ab8945cd2f54917be357d134db9cc1eb039e59d1606dc1e60cb1d9d36"}, + {file = "typing-3.7.4.1-py3-none-any.whl", hash = "sha256:f38d83c5a7a7086543a0f649564d661859c5146a85775ab90c0d2f93ffaa9714"}, + {file = "typing-3.7.4.1.tar.gz", hash = "sha256:91dfe6f3f706ee8cc32d38edbbf304e9b7583fb37108fef38229617f8b3eba23"}, +] +typing-extensions = [ + {file = "typing_extensions-3.7.4-py2-none-any.whl", hash = "sha256:b1edbbf0652660e32ae780ac9433f4231e7339c7f9a8057d0f042fcbcea49b87"}, + {file = "typing_extensions-3.7.4-py3-none-any.whl", hash = "sha256:d8179012ec2c620d3791ca6fe2bf7979d979acdbef1fca0bc56b37411db682ed"}, + {file = "typing_extensions-3.7.4.tar.gz", hash = "sha256:2ed632b30bb54fc3941c382decfd0ee4148f5c591651c9272473fea2c6397d95"}, +] +virtualenv = [ + {file = "virtualenv-16.7.7-py2.py3-none-any.whl", hash = "sha256:11cb4608930d5fd3afb545ecf8db83fa50e1f96fc4fca80c94b07d2c83146589"}, + {file = "virtualenv-16.7.7.tar.gz", hash = "sha256:d257bb3773e48cac60e475a19b608996c73f4d333b3ba2e4e57d5ac6134e0136"}, +] +wcwidth = [ + {file = "wcwidth-0.1.7-py2.py3-none-any.whl", hash = "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"}, + {file = "wcwidth-0.1.7.tar.gz", hash = "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e"}, +] +zipp = [ + {file = "zipp-0.6.0-py2.py3-none-any.whl", hash = "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335"}, + {file = "zipp-0.6.0.tar.gz", hash = "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e"}, +] diff --git a/pyproject.toml b/pyproject.toml index cfd2bf8..ce39ed7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,11 +26,11 @@ pyparsing = "^2.4" flake8 = "^3.7" mypy = "^0.740.0" pytest = "^5.2" -yapf = "^0.28.0" pytest-datadir = "^1.3" tox = "^3.14" isort = "^4.3" pytest-cov = "^2.8" +black = "^19.10b0" [tool.poetry.scripts] cmake-format = "cmake_language_server.formatter:main" diff --git a/src/cmake_language_server/__init__.py b/src/cmake_language_server/__init__.py index 10939f0..b3f4756 100644 --- a/src/cmake_language_server/__init__.py +++ b/src/cmake_language_server/__init__.py @@ -1 +1 @@ -__version__ = '0.1.2' +__version__ = "0.1.2" diff --git a/src/cmake_language_server/api.py b/src/cmake_language_server/api.py index 73ea390..2b80082 100644 --- a/src/cmake_language_server/api.py +++ b/src/cmake_language_server/api.py @@ -12,10 +12,10 @@ logger = logging.getLogger(__name__) def _tidy_doc(doc: str) -> str: doc = doc.strip() - doc = re.sub(r':.+?:`(.+?)`', r'\1', doc) - doc = re.sub(r'``([^`]+)``', r'`\1`', doc) - doc = doc.replace('\n', ' ') - doc = doc.replace('. ', '. ') + doc = re.sub(r":.+?:`(.+?)`", r"\1", doc) + doc = re.sub(r"``([^`]+)``", r"`\1`", doc) + doc = doc.replace("\n", " ") + doc = doc.replace(". ", ". ") return doc @@ -49,78 +49,82 @@ class API(object): return False self.query_json.parent.mkdir(parents=True, exist_ok=True) - with self.query_json.open('w') as fp: - fp.write('''\ + with self.query_json.open("w") as fp: + fp.write( + """\ { "requests": [ {"kind": "codemodel", "version": 2}, {"kind": "cache", "version": 2}, {"kind": "cmakeFiles", "version": 1} ] -}''') +}""" + ) - proc = subprocess.run([self._cmake, str(self._build)], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - encoding='utf-8', - universal_newlines=True) + proc = subprocess.run( + [self._cmake, str(self._build)], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + encoding="utf-8", + universal_newlines=True, + ) self.query_json.unlink() self.query_json.parent.rmdir() if proc.returncode != 0: - logging.error( - f'cmake exited with {proc.returncode}: {proc.stderr}') + logging.error(f"cmake exited with {proc.returncode}: {proc.stderr}") return False return True def read_reply(self) -> bool: - reply = self._build / '.cmake' / 'api' / 'v1' / 'reply' - indices = sorted(reply.glob('index-*.json')) + reply = self._build / ".cmake" / "api" / "v1" / "reply" + indices = sorted(reply.glob("index-*.json")) if not indices: - logger.error('no reply') + logger.error("no reply") return False with indices[-1].open() as fp: index = json.load(fp) try: - responses = index['reply'][f'client-{self._uuid}']['query.json'][ - 'responses'] + responses = index["reply"][f"client-{self._uuid}"]["query.json"][ + "responses" + ] except KeyError: - logger.error('no rensponse') + logger.error("no rensponse") return False for response in responses: - if response['kind'] == 'codemodel': - self._read_codemodel(reply / response['jsonFile']) - elif response['kind'] == 'cache': - self._read_cache(reply / response['jsonFile']) - elif response['kind'] == 'cmakeFiles': - self._read_cmake_files(reply / response['jsonFile']) + if response["kind"] == "codemodel": + self._read_codemodel(reply / response["jsonFile"]) + elif response["kind"] == "cache": + self._read_cache(reply / response["jsonFile"]) + elif response["kind"] == "cmakeFiles": + self._read_cmake_files(reply / response["jsonFile"]) return True def _read_codemodel(self, codemodelpath: Path): with (codemodelpath).open() as fp: codemodel = json.load(fp) - config = codemodel['configurations'][0] - self._targets[:] = [x['name'] for x in config['targets']] + config = codemodel["configurations"][0] + self._targets[:] = [x["name"] for x in config["targets"]] def _read_cache(self, cachepath: Path): with cachepath.open() as fp: cache = json.load(fp) self._cached_variables.clear() - for entry in cache['entries']: - name = entry['name'] - value = self._truncate_variable(entry['value']) - properties = {x['name']: x['value'] for x in entry['properties']} - helpstring = properties.get('HELPSTRING', '') + for entry in cache["entries"]: + name = entry["name"] + value = self._truncate_variable(entry["value"]) + properties = {x["name"]: x["value"] for x in entry["properties"]} + helpstring = properties.get("HELPSTRING", "") doc = [] if helpstring: doc.append(helpstring) if value: - doc.append(f'`{value}`') - self._cached_variables[name] = '\n\n'.join(doc) + doc.append(f"`{value}`") + self._cached_variables[name] = "\n\n".join(doc) def _read_cmake_files(self, jsonpath: Path): - '''inspect generated list files''' + """inspect generated list files""" if not self._builtin_variables or self._generated_list_parsed: return @@ -130,44 +134,46 @@ class API(object): # inspect generated list files with tempfile.TemporaryDirectory() as tmpdirname: - tmplist = Path(tmpdirname) / 'dump.cmake' - with tmplist.open('w') as fp: - for listfile in cmake_files['inputs']: - if not listfile.get('isGenerated', False): + tmplist = Path(tmpdirname) / "dump.cmake" + with tmplist.open("w") as fp: + for listfile in cmake_files["inputs"]: + if not listfile.get("isGenerated", False): continue - path = listfile['path'] - fp.write(f'include({path})\n') - fp.write(''' + path = listfile["path"] + fp.write(f"include({path})\n") + fp.write( + """ get_cmake_property(variables VARIABLES) foreach (variable ${variables}) message("${variable}=${${variable}}") endforeach() -''') +""" + ) p = subprocess.run( - [self._cmake, '-P', str(tmplist)], + [self._cmake, "-P", str(tmplist)], stdout=subprocess.PIPE, stderr=subprocess.PIPE, - cwd=cmake_files['paths']['source'], - encoding='utf-8', - universal_newlines=True) + cwd=cmake_files["paths"]["source"], + encoding="utf-8", + universal_newlines=True, + ) if p.returncode != 0: return - for line in p.stderr.split('\n'): + for line in p.stderr.split("\n"): line = line.strip() if not line: continue - k, v = line.split('=', 1) - if k.startswith('CMAKE_ARG'): + k, v = line.split("=", 1) + if k.startswith("CMAKE_ARG"): continue v = self._truncate_variable(v) if k in self._builtin_variables: - self._builtin_variables[k] += f'\n\n`{v}`' + self._builtin_variables[k] += f"\n\n`{v}`" else: - for pattern, doc in self._builtin_variable_template.items( - ): + for pattern, doc in self._builtin_variable_template.items(): if pattern.fullmatch(k): - self._builtin_variables[k] = f'{doc}\n\n`{v}`' + self._builtin_variables[k] = f"{doc}\n\n`{v}`" break else: # ignore variable with no document @@ -177,12 +183,19 @@ endforeach() @property def query_json(self) -> Path: - return (self._build / '.cmake' / 'api' / 'v1' / 'query' / - f'client-{self._uuid}' / 'query.json') + return ( + self._build + / ".cmake" + / "api" + / "v1" + / "query" + / f"client-{self._uuid}" + / "query.json" + ) @property def cmake_cache(self) -> Path: - return self._build / 'CMakeCache.txt' + return self._build / "CMakeCache.txt" def parse_doc(self) -> None: self._parse_commands() @@ -190,81 +203,95 @@ endforeach() self._parse_modules() def _parse_commands(self) -> None: - p = subprocess.run([self._cmake, '--help-commands'], - stdout=subprocess.PIPE, - encoding='utf-8', - universal_newlines=True) + p = subprocess.run( + [self._cmake, "--help-commands"], + stdout=subprocess.PIPE, + encoding="utf-8", + universal_newlines=True, + ) if p.returncode != 0: return matches = re.finditer( - r''' + r""" (?P.+)\n -+\n+? [\s\S]*? (?P(?P=command)\s*\([^)]*\)) -''', p.stdout, re.VERBOSE) +""", + p.stdout, + re.VERBOSE, + ) self._builtin_commands.clear() for match in matches: - command = match.group('command') - signature = match.group('signature') - signature = re.sub(r'^ ', r'', signature, flags=re.MULTILINE) - self._builtin_commands[ - command] = '```cmake\n' + signature + '\n```' + command = match.group("command") + signature = match.group("signature") + signature = re.sub(r"^ ", r"", signature, flags=re.MULTILINE) + self._builtin_commands[command] = "```cmake\n" + signature + "\n```" def _parse_variables(self) -> None: - p = subprocess.run([self._cmake, '--help-variables'], - stdout=subprocess.PIPE, - encoding='utf-8', - universal_newlines=True) + p = subprocess.run( + [self._cmake, "--help-variables"], + stdout=subprocess.PIPE, + encoding="utf-8", + universal_newlines=True, + ) if p.returncode != 0: return matches = re.finditer( - r''' + r""" (?P.+)\n -+\n\n (?P[\s\S]+?)(?:\n\n|$) -''', p.stdout, re.VERBOSE) +""", + p.stdout, + re.VERBOSE, + ) self._builtin_variables.clear() for match in matches: - variable = match.group('variable') - doc = _tidy_doc(match.group('doc')) - if variable == 'CMAKE_MATCH_': + variable = match.group("variable") + doc = _tidy_doc(match.group("doc")) + if variable == "CMAKE_MATCH_": for i in range(10): - self._builtin_variables[f'CMAKE_MATCH_{i}'] = doc - elif '<' in variable: - variable = re.sub(r'<[^>]+>', r'[^_]+', variable) + self._builtin_variables[f"CMAKE_MATCH_{i}"] = doc + elif "<" in variable: + variable = re.sub(r"<[^>]+>", r"[^_]+", variable) pattern = re.compile(variable) self._builtin_variable_template[pattern] = doc else: self._builtin_variables[variable] = doc def _parse_modules(self) -> None: - p = subprocess.run([self._cmake, '--help-modules'], - stdout=subprocess.PIPE, - encoding='utf-8', - universal_newlines=True) + p = subprocess.run( + [self._cmake, "--help-modules"], + stdout=subprocess.PIPE, + encoding="utf-8", + universal_newlines=True, + ) if p.returncode != 0: return matches = re.finditer( - r''' + r""" (?P.+)\n -+\n+? (?:(?P
\w[\w\s]+)\n\^+\n+?)? (?P.(?:.|\n)+?\n\n) -''', p.stdout + '\n\n', re.VERBOSE) +""", + p.stdout + "\n\n", + re.VERBOSE, + ) self._builtin_modules.clear() for match in matches: - module = match.group('module') - header = match.group('header') - doc = _tidy_doc(match.group('doc')) - if header is not None and header != 'Overview': - doc = '' + module = match.group("module") + header = match.group("header") + doc = _tidy_doc(match.group("doc")) + if header is not None and header != "Overview": + doc = "" self._builtin_modules[module] = doc def get_command_doc(self, command: str) -> Optional[str]: @@ -281,28 +308,27 @@ endforeach() return self._builtin_variables.get(variable) def search_variable(self, variable: str) -> List[str]: - cached = frozenset(x for x in self._cached_variables - if x.startswith(variable)) - builtin = frozenset(x for x in self._builtin_variables - if x.startswith(variable)) + cached = frozenset(x for x in self._cached_variables if x.startswith(variable)) + builtin = frozenset( + x for x in self._builtin_variables if x.startswith(variable) + ) return list(cached | builtin) def get_module_doc(self, module: str, package: bool) -> Optional[str]: if package: - return self._builtin_modules.get('Find' + module) + return self._builtin_modules.get("Find" + module) return self._builtin_modules.get(module) def search_module(self, module: str, package: bool) -> List[str]: if package: - module = 'Find' + module - return [ - x[4:] for x in self._builtin_modules if x.startswith(module) - ] + module = "Find" + module + return [x[4:] for x in self._builtin_modules if x.startswith(module)] return [ - x for x in self._builtin_modules - if x.startswith(module) and not x.startswith('Find') + x + for x in self._builtin_modules + if x.startswith(module) and not x.startswith("Find") ] def search_target(self, target: str) -> List[str]: @@ -310,4 +336,4 @@ endforeach() def _truncate_variable(self, v: str) -> str: width = 70 - return v[:width] + (v[width:] and '...') + return v[:width] + (v[width:] and "...") diff --git a/src/cmake_language_server/formatter.py b/src/cmake_language_server/formatter.py index a5238c3..ef645c1 100644 --- a/src/cmake_language_server/formatter.py +++ b/src/cmake_language_server/formatter.py @@ -7,39 +7,51 @@ class Formatter(object): indnt: str lower_identifier: bool - def __init__(self, indent=' ', lower_identifier=True): + def __init__(self, indent=" ", lower_identifier=True): self.indent = indent self.lower_identifier = lower_identifier def format(self, tokens: TokenList) -> str: - cmds: List[str] = [''] + cmds: List[str] = [""] indnet_level = 0 for token in tokens: if isinstance(token, tuple): raw_identifier = token[0] identifier = raw_identifier.lower() - if identifier in ('elseif', 'else', 'endif', 'endforeach', - 'endwhile', 'endmacro', 'endfunction'): + if identifier in ( + "elseif", + "else", + "endif", + "endforeach", + "endwhile", + "endmacro", + "endfunction", + ): if indnet_level > 0: indnet_level -= 1 cmds[-1] = self.indent * indnet_level - cmds[-1] += (identifier - if self.lower_identifier else raw_identifier) + cmds[-1] += identifier if self.lower_identifier else raw_identifier args = self._format_args(token[1]) if len(args) < 2: - cmds[-1] += '(' + ''.join(args) + ')' + cmds[-1] += "(" + "".join(args) + ")" else: - cmds[-1] += '(\n' + cmds[-1] += "(\n" for arg in args: - cmds[-1] += self.indent * (indnet_level + - 1) + arg + '\n' - cmds[-1] += self.indent * indnet_level + ')' - if identifier in ('if', 'elseif', 'else', 'foreach', 'while', - 'macro', 'function'): + cmds[-1] += self.indent * (indnet_level + 1) + arg + "\n" + cmds[-1] += self.indent * indnet_level + ")" + if identifier in ( + "if", + "elseif", + "else", + "foreach", + "while", + "macro", + "function", + ): indnet_level += 1 - elif token == '\n': - cmds.append('') - elif token[0] == '#': + elif token == "\n": + cmds.append("") + elif token[0] == "#": if cmds[-1]: cmds[-1] += token else: @@ -48,70 +60,67 @@ class Formatter(object): cmds[-1] += token cmds = self._strip_line(cmds) - return '\n'.join(cmds) + '\n' + return "\n".join(cmds) + "\n" def _format_args(self, args: List[str]) -> List[str]: - lines = [''] + lines = [""] for i in range(len(args)): arg = args[i] - if arg[0] == '#': + if arg[0] == "#": lines[-1] += arg - elif arg[0] == '\n': - lines.append('') + elif arg[0] == "\n": + lines.append("") elif arg.isspace(): if lines[-1]: - if i + 1 < len(args) and args[i + 1][0] == '#': + if i + 1 < len(args) and args[i + 1][0] == "#": lines[-1] += arg else: - lines[-1] += ' ' + lines[-1] += " " else: lines[-1] += arg return self._strip_line(lines) def _strip_line(self, lines: List[str]) -> List[str]: - '''Delete empty lines at the start/end of the input''' + """Delete empty lines at the start/end of the input""" ret: List[str] = [] for line in lines: line = line.rstrip() - if line != '' or len(ret) > 0: + if line != "" or len(ret) > 0: ret.append(line) - while ret and ret[-1] == '': + while ret and ret[-1] == "": del ret[-1] return ret def main(args: List[str] = None): + import sys from argparse import ArgumentParser from difflib import unified_diff from pathlib import Path - import sys + from . import __version__ from .parser import ListParser parser = ArgumentParser( - description='Format CMake list files.', - epilog=''' + description="Format CMake list files.", + epilog=""" If no arguments are specified, it formats the code from - standard input and writes the result to the standard output.''', + standard input and writes the result to the standard output.""", ) - parser.add_argument('lists', type=Path, nargs='*', help='CMake list files') + parser.add_argument("lists", type=Path, nargs="*", help="CMake list files") group = parser.add_mutually_exclusive_group() - group.add_argument('-i', - '--inplace', - action='store_true', - help='inplace edit') - group.add_argument('-d', '--diff', action='store_true', help='show diff') - parser.add_argument('--version', - action='version', - version=f'%(prog)s {__version__}') + group.add_argument("-i", "--inplace", action="store_true", help="inplace edit") + group.add_argument("-d", "--diff", action="store_true", help="show diff") + parser.add_argument( + "--version", action="version", version=f"%(prog)s {__version__}" + ) args = parser.parse_args(args) if not args.lists and args.inplace: - print('error: cannot use -i when no arguments are specified.', - file=sys.stderr) + print("error: cannot use -i when no arguments are specified.", file=sys.stderr) return if not args.lists: args.lists.append(None) @@ -120,7 +129,7 @@ def main(args: List[str] = None): formatter = Formatter() for listpath in args.lists: if listpath is None: - listpath = '(stdin)' + listpath = "(stdin)" content = sys.stdin.read() else: with listpath.open() as fp: @@ -130,14 +139,18 @@ def main(args: List[str] = None): if args.inplace: if not remain: - with listpath.open('w') as fp: + with listpath.open("w") as fp: fp.write(formatted) elif args.diff: - diff = unified_diff(content.splitlines(True), - formatted.splitlines(True), str(listpath), - str(listpath), '(before formatting)', - '(after formatting)') - diffstr = ''.join(diff) - print(diffstr, end='') + diff = unified_diff( + content.splitlines(True), + formatted.splitlines(True), + str(listpath), + str(listpath), + "(before formatting)", + "(after formatting)", + ) + diffstr = "".join(diff) + print(diffstr, end="") else: - print(formatted, end='') + print(formatted, end="") diff --git a/src/cmake_language_server/parser.py b/src/cmake_language_server/parser.py index 8188a3b..62e189a 100644 --- a/src/cmake_language_server/parser.py +++ b/src/cmake_language_server/parser.py @@ -11,8 +11,8 @@ class ListParser(object): _parser: pp.ParserElement def __init__(self): - newline = '\n' - space_plus = pp.Regex('[ \t]+') + newline = "\n" + space_plus = pp.Regex("[ \t]+") space_star = pp.Optional(space_plus) quoted_element = pp.Regex(r'[^\\"]|\\[^A-Za-z0-9]|\\[trn]') @@ -22,10 +22,10 @@ class ListParser(object): def action_bracket_open(tokens: pp.ParseResults): nonlocal bracket_content - marker = ']' + '=' * (len(tokens[0]) - 2) + ']' + marker = "]" + "=" * (len(tokens[0]) - 2) + "]" bracket_content <<= pp.SkipTo(marker, include=True) - bracket_open = pp.Regex(r'\[=*\[').setParseAction(action_bracket_open) + bracket_open = pp.Regex(r"\[=*\[").setParseAction(action_bracket_open) bracket_argument = pp.Combine(bracket_open + bracket_content) unquoted_element = pp.Regex(r'[^\s()#"\\]|\\[^A-Za-z0-9]|\\[trn]') @@ -33,25 +33,29 @@ class ListParser(object): argument = bracket_argument | quoted_argument | unquoted_argument - line_comment = pp.Combine('#' + ~bracket_open + - pp.SkipTo(pp.LineEnd())) - bracket_comment = pp.Combine('#' + bracket_argument) - line_ending = (space_star + - pp.ZeroOrMore(bracket_comment + space_star) + - pp.Optional(line_comment) + (newline | pp.lineEnd)) + line_comment = pp.Combine("#" + ~bracket_open + pp.SkipTo(pp.LineEnd())) + bracket_comment = pp.Combine("#" + bracket_argument) + line_ending = ( + space_star + + pp.ZeroOrMore(bracket_comment + space_star) + + pp.Optional(line_comment) + + (newline | pp.lineEnd) + ) - identifier = pp.Word(pp.alphas + '_', pp.alphanums + '_') + identifier = pp.Word(pp.alphas + "_", pp.alphanums + "_") arguments = pp.Forward() - arguments << pp.ZeroOrMore(argument | line_ending | space_plus - | '(' + arguments + ')').leaveWhitespace() + arguments << pp.ZeroOrMore( + argument | line_ending | space_plus | "(" + arguments + ")" + ).leaveWhitespace() arguments = pp.Group(arguments) - PAREN_L, PAREN_R = map(pp.Suppress, '()') + PAREN_L, PAREN_R = map(pp.Suppress, "()") command_invocation = ( - identifier + space_star.suppress() + PAREN_L + arguments + - PAREN_R).setParseAction(lambda t: (t[0], t[1].asList())) + identifier + space_star.suppress() + PAREN_L + arguments + PAREN_R + ).setParseAction(lambda t: (t[0], t[1].asList())) - file_element = (space_star + command_invocation + line_ending - | line_ending).leaveWhitespace() + file_element = ( + space_star + command_invocation + line_ending | line_ending + ).leaveWhitespace() file = pp.ZeroOrMore(file_element) self._parser = file diff --git a/src/cmake_language_server/server.py b/src/cmake_language_server/server.py index e8b6309..1aa2118 100644 --- a/src/cmake_language_server/server.py +++ b/src/cmake_language_server/server.py @@ -3,14 +3,31 @@ import re from pathlib import Path from typing import List, Optional, Tuple -from pygls.features import (COMPLETION, FORMATTING, HOVER, INITIALIZE, - INITIALIZED, TEXT_DOCUMENT_DID_SAVE) +from pygls.features import ( + COMPLETION, + FORMATTING, + HOVER, + INITIALIZE, + INITIALIZED, + TEXT_DOCUMENT_DID_SAVE, +) from pygls.server import LanguageServer -from pygls.types import (CompletionItem, CompletionItemKind, CompletionList, - CompletionParams, CompletionTriggerKind, - DocumentFormattingParams, Hover, InitializeParams, - MarkupContent, MarkupKind, Position, Range, - TextDocumentPositionParams, TextEdit) +from pygls.types import ( + CompletionItem, + CompletionItemKind, + CompletionList, + CompletionParams, + CompletionTriggerKind, + DocumentFormattingParams, + Hover, + InitializeParams, + MarkupContent, + MarkupKind, + Position, + Range, + TextDocumentPositionParams, + TextEdit, +) from .api import API from .formatter import Formatter @@ -33,32 +50,34 @@ class CMakeLanguageServer(LanguageServer): def initialize(params: InitializeParams): opts = params.initializationOptions - cmake = getattr(opts, 'cmakeExecutable', 'cmake') - builddir = getattr(opts, 'buildDirectory', '') - logging.info(f'cmakeExecutable={cmake}, buildDirectory={builddir}') + cmake = getattr(opts, "cmakeExecutable", "cmake") + builddir = getattr(opts, "buildDirectory", "") + logging.info(f"cmakeExecutable={cmake}, buildDirectory={builddir}") self._api = API(cmake, Path(builddir)) self._api.parse_doc() - trigger_characters = ['{', '('] + trigger_characters = ["{", "("] @self.feature(COMPLETION, trigger_characters=trigger_characters) def completions(params: CompletionParams): - if (hasattr(params, 'context') and params.context.triggerKind == - CompletionTriggerKind.TriggerCharacter): - token = '' + if ( + hasattr(params, "context") + and params.context.triggerKind == CompletionTriggerKind.TriggerCharacter + ): + token = "" trigger = params.context.triggerCharacter else: - line = self._cursor_line(params.textDocument.uri, - params.position) + line = self._cursor_line(params.textDocument.uri, params.position) idx = params.position.character - 1 if 0 <= idx < len(line) and line[idx] in trigger_characters: - token = '' + token = "" trigger = line[idx] else: - word = self._cursor_word(params.textDocument.uri, - params.position, False) - token = '' if word is None else word[0] + word = self._cursor_word( + params.textDocument.uri, params.position, False + ) + token = "" if word is None else word[0] trigger = None items: List[CompletionItem] = [] @@ -66,46 +85,60 @@ class CMakeLanguageServer(LanguageServer): if trigger is None: commands = self._api.search_command(token) items.extend( - CompletionItem(x, - CompletionItemKind.Function, - documentation=self._api.get_command_doc(x), - insert_text=x) for x in commands) + CompletionItem( + x, + CompletionItemKind.Function, + documentation=self._api.get_command_doc(x), + insert_text=x, + ) + for x in commands + ) - if trigger is None or trigger == '{': + if trigger is None or trigger == "{": variables = self._api.search_variable(token) items.extend( - CompletionItem(x, - CompletionItemKind.Variable, - documentation=self._api.get_variable_doc(x), - insert_text=x) for x in variables) + CompletionItem( + x, + CompletionItemKind.Variable, + documentation=self._api.get_variable_doc(x), + insert_text=x, + ) + for x in variables + ) if trigger is None: targets = self._api.search_target(token) items.extend( CompletionItem(x, CompletionItemKind.Class, insert_text=x) - for x in targets) + for x in targets + ) - if trigger == '(': - func = self._cursor_function(params.textDocument.uri, - params.position) + if trigger == "(": + func = self._cursor_function(params.textDocument.uri, params.position) if func is not None: func = func.lower() - if func == 'include': + if func == "include": modules = self._api.search_module(token, False) items.extend( - CompletionItem(x, - CompletionItemKind.Module, - documentation=self._api. - get_module_doc(x, False), - insert_text=x) for x in modules) - elif func == 'find_package': + CompletionItem( + x, + CompletionItemKind.Module, + documentation=self._api.get_module_doc(x, False), + insert_text=x, + ) + for x in modules + ) + elif func == "find_package": modules = self._api.search_module(token, True) items.extend( - CompletionItem(x, - CompletionItemKind.Module, - documentation=self._api. - get_module_doc(x, True), - insert_text=x) for x in modules) + CompletionItem( + x, + CompletionItemKind.Module, + documentation=self._api.get_module_doc(x, True), + insert_text=x, + ) + for x in modules + ) return CompletionList(False, items) @@ -115,20 +148,16 @@ class CMakeLanguageServer(LanguageServer): content = doc.source tokens, remain = self._parser.parse(content) if remain: - self.show_message('CMake parser failed') + self.show_message("CMake parser failed") return None formatted = Formatter().format(tokens) - lines = content.count('\n') - return [ - TextEdit(Range(Position(0, 0), Position(lines + 1, 0)), - formatted) - ] + lines = content.count("\n") + return [TextEdit(Range(Position(0, 0), Position(lines + 1, 0)), formatted)] @self.feature(HOVER) def hover(params: TextDocumentPositionParams): - word = self._cursor_word(params.textDocument.uri, params.position, - True) + word = self._cursor_word(params.textDocument.uri, params.position, True) if not word: return None @@ -154,43 +183,46 @@ class CMakeLanguageServer(LanguageServer): def _cursor_function(self, uri: str, position: Position) -> Optional[str]: doc = self.workspace.get_document(uri) - lines = doc.source.split('\n')[:position.line + 1] - lines[-1] = lines[-1][:position.character - 1].strip() - words = re.split(r'[\s\n()]+', '\n'.join(lines)) + lines = doc.source.split("\n")[: position.line + 1] + lines[-1] = lines[-1][: position.character - 1].strip() + words = re.split(r"[\s\n()]+", "\n".join(lines)) return words[-1] if words else None def _cursor_line(self, uri: str, position: Position) -> str: doc = self.workspace.get_document(uri) content = doc.source - line = content.split('\n')[position.line] + line = content.split("\n")[position.line] return line - def _cursor_word(self, - uri: str, - position: Position, - include_all: bool = True) -> Optional[Tuple[str, Range]]: + def _cursor_word( + self, uri: str, position: Position, include_all: bool = True + ) -> Optional[Tuple[str, Range]]: line = self._cursor_line(uri, position) cursor = position.character - for m in re.finditer(r'\w+', line): + for m in re.finditer(r"\w+", line): end = m.end() if include_all else cursor if m.start() <= cursor <= m.end(): - word = (line[m.start():end], - Range(Position(position.line, m.start()), - Position(position.line, end))) + word = ( + line[m.start() : end], + Range( + Position(position.line, m.start()), Position(position.line, end) + ), + ) return word return None def main(args=None): from argparse import ArgumentParser + from . import __version__ - parser = ArgumentParser(description='CMake Language Server') - parser.add_argument('--version', - action='version', - version=f'%(prog)s {__version__}') + parser = ArgumentParser(description="CMake Language Server") + parser.add_argument( + "--version", action="version", version=f"%(prog)s {__version__}" + ) args = parser.parse_args(args) logging.basicConfig(level=logging.INFO) - logging.getLogger('pygls').setLevel(logging.WARNING) + logging.getLogger("pygls").setLevel(logging.WARNING) CMakeLanguageServer().start_io() diff --git a/tests/conftest.py b/tests/conftest.py index aafea51..ce8afc7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -14,18 +14,20 @@ from cmake_language_server.server import CMakeLanguageServer @pytest.fixture() def cmake_build(shared_datadir): - source = shared_datadir / 'cmake' - build = source / 'build' + source = shared_datadir / "cmake" + build = source / "build" build.mkdir() - p = run(['cmake', str(source)], - cwd=build, - stdout=PIPE, - stderr=PIPE, - universal_newlines=True) + p = run( + ["cmake", str(source)], + cwd=build, + stdout=PIPE, + stderr=PIPE, + universal_newlines=True, + ) if p.returncode != 0: - logging.error('env:\n' + pprint.pformat(os.environ)) - logging.error('stdout:\n' + p.stdout) - logging.error('stderr:\n' + p.stderr) + logging.error("env:\n" + pprint.pformat(os.environ)) + logging.error("stdout:\n" + p.stdout) + logging.error("stderr:\n" + p.stderr) raise RuntimeError("CMake failed") yield build @@ -40,7 +42,7 @@ def client_server(): # disable `close()` to avoid error messages close = ls.loop.close ls.loop.close = lambda: None - ls.start_io(os.fdopen(fdr, 'rb'), os.fdopen(fdw, 'wb')) + ls.start_io(os.fdopen(fdr, "rb"), os.fdopen(fdw, "wb")) ls.loop.close = close server = CMakeLanguageServer(asyncio.new_event_loop()) diff --git a/tests/test_api.py b/tests/test_api.py index a4ce60d..2e4a141 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -4,109 +4,115 @@ from cmake_language_server.api import API def test_query_with_cache(cmake_build): - api = API('cmake', cmake_build) + api = API("cmake", cmake_build) assert api.query() - query = cmake_build / '.cmake' / 'api' / 'v1' / 'query' + query = cmake_build / ".cmake" / "api" / "v1" / "query" assert query.exists() - reply = cmake_build / '.cmake' / 'api' / 'v1' / 'reply' + reply = cmake_build / ".cmake" / "api" / "v1" / "reply" assert reply.exists() def test_query_without_cache(cmake_build): - api = API('cmake', cmake_build) - (cmake_build / 'CMakeCache.txt').unlink() + api = API("cmake", cmake_build) + (cmake_build / "CMakeCache.txt").unlink() assert not api.query() def test_read_variable(cmake_build): - api = API('cmake', cmake_build) + api = API("cmake", cmake_build) assert api.query() assert api.read_reply() - assert api.get_variable_doc('testproject_BINARY_DIR') + assert api.get_variable_doc("testproject_BINARY_DIR") def test_read_cmake_files(cmake_build): - api = API('cmake', cmake_build) + api = API("cmake", cmake_build) api.parse_doc() assert api.query() api.read_reply() import platform + system = platform.system() - if system == 'Linux': - assert 'GNU' in api.get_variable_doc('CMAKE_CXX_COMPILER_ID') - elif system == 'Windows': - assert 'MSVC' in api.get_variable_doc('CMAKE_CXX_COMPILER_ID') - elif system == 'Darwin': - assert 'Clang' in api.get_variable_doc('CMAKE_CXX_COMPILER_ID') + if system == "Linux": + assert "GNU" in api.get_variable_doc("CMAKE_CXX_COMPILER_ID") + elif system == "Windows": + assert "MSVC" in api.get_variable_doc("CMAKE_CXX_COMPILER_ID") + elif system == "Darwin": + assert "Clang" in api.get_variable_doc("CMAKE_CXX_COMPILER_ID") else: - raise RuntimeError('Unexpected system') + raise RuntimeError("Unexpected system") def test_parse_commands(cmake_build): - api = API('cmake', cmake_build) + api = API("cmake", cmake_build) api.parse_doc() - p = subprocess.run(['cmake', '--help-command-list'], - universal_newlines=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - commands = p.stdout.strip().split('\n') + p = subprocess.run( + ["cmake", "--help-command-list"], + universal_newlines=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + commands = p.stdout.strip().split("\n") for command in commands: - assert api.get_command_doc(command) is not None, f'{command} not found' + assert api.get_command_doc(command) is not None, f"{command} not found" - assert 'break()' in api.get_command_doc('break') - assert api.get_command_doc('not_existing_command') is None + assert "break()" in api.get_command_doc("break") + assert api.get_command_doc("not_existing_command") is None def test_parse_variables(cmake_build): - api = API('cmake', cmake_build) + api = API("cmake", cmake_build) api.parse_doc() - p = subprocess.run(['cmake', '--help-variable-list'], - universal_newlines=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - variables = p.stdout.strip().split('\n') + p = subprocess.run( + ["cmake", "--help-variable-list"], + universal_newlines=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + variables = p.stdout.strip().split("\n") for variable in variables: - if '<' in variable: + if "<" in variable: continue - assert api.get_variable_doc( - variable) is not None, f'{variable} not found' + assert api.get_variable_doc(variable) is not None, f"{variable} not found" - assert api.get_variable_doc('BUILD_SHARED_LIBS') is not None - assert api.get_variable_doc('not_existing_variable') is None + assert api.get_variable_doc("BUILD_SHARED_LIBS") is not None + assert api.get_variable_doc("not_existing_variable") is None def test_parse_modules(cmake_build): - api = API('cmake', cmake_build) + api = API("cmake", cmake_build) api.parse_doc() - p = subprocess.run(['cmake', '--help-module-list'], - universal_newlines=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - modules = p.stdout.strip().split('\n') + p = subprocess.run( + ["cmake", "--help-module-list"], + universal_newlines=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + modules = p.stdout.strip().split("\n") for module in modules: - if module.startswith('Find'): - assert api.get_module_doc(module[4:], - True) is not None, f'{module} not found' + if module.startswith("Find"): + assert ( + api.get_module_doc(module[4:], True) is not None + ), f"{module} not found" else: - assert api.get_module_doc(module, - False) is not None, f'{module} not found' + assert api.get_module_doc(module, False) is not None, f"{module} not found" - assert api.get_module_doc('GoogleTest', False) is not None - assert api.get_module_doc('GoogleTest', True) is None - assert api.search_module('GoogleTest', False) == ['GoogleTest'] - assert api.search_module('GoogleTest', True) == [] - assert api.get_module_doc('Boost', False) is None - assert api.get_module_doc('Boost', True) is not None - assert api.search_module('Boost', False) == [] - assert api.search_module('Boost', True) == ['Boost'] + assert api.get_module_doc("GoogleTest", False) is not None + assert api.get_module_doc("GoogleTest", True) is None + assert api.search_module("GoogleTest", False) == ["GoogleTest"] + assert api.search_module("GoogleTest", True) == [] + assert api.get_module_doc("Boost", False) is None + assert api.get_module_doc("Boost", True) is not None + assert api.search_module("Boost", False) == [] + assert api.search_module("Boost", True) == ["Boost"] diff --git a/tests/test_fomatter.py b/tests/test_fomatter.py index 153829f..8869533 100644 --- a/tests/test_fomatter.py +++ b/tests/test_fomatter.py @@ -15,50 +15,57 @@ def make_formatter_test(liststr: str, expect: str): return test -test_command = make_formatter_test('a()', 'a()\n') -test_command_tolower = make_formatter_test('A()', 'a()\n') -test_remove_space = make_formatter_test(''' +test_command = make_formatter_test("a()", "a()\n") +test_command_tolower = make_formatter_test("A()", "a()\n") +test_remove_space = make_formatter_test( + """ #a b ( c ) # d -''', '''\ +""", + """\ #a b(c) # d -''') +""", +) test_indent_if = make_formatter_test( - ''' + """ if() a() # a else() # b b() endif() -''', '''\ +""", + """\ if() a() # a else() # b b() endif() -''') +""", +) test_indent_if_nested = make_formatter_test( - ''' + """ if() if() a() b() endif() endif() -''', '''\ +""", + """\ if() if() a() b() endif() endif() -''') -test_argument = make_formatter_test('a( b c d)', 'a(b c d)\n') +""", +) +test_argument = make_formatter_test("a( b c d)", "a(b c d)\n") test_argument_multiline = make_formatter_test( - ''' + """ if() a(b c d # e @@ -66,7 +73,8 @@ f # g ) # h endif() -''', '''\ +""", + """\ if() a( b c @@ -75,7 +83,8 @@ if() # g ) # h endif() -''') +""", +) @contextmanager @@ -87,70 +96,70 @@ def mock_stdin(buf: str): def test_main_stdin(capsys): - with mock_stdin(' a()'): + with mock_stdin(" a()"): main([]) captured = capsys.readouterr() - assert captured.out == 'a()\n' - assert captured.err == '' + assert captured.out == "a()\n" + assert captured.err == "" def test_main_stdin_diff(capsys): - with mock_stdin(' a()'): - main(['-d']) + with mock_stdin(" a()"): + main(["-d"]) captured = capsys.readouterr() - assert '- a()' in captured.out - assert '+a()' in captured.out - assert captured.err == '' + assert "- a()" in captured.out + assert "+a()" in captured.out + assert captured.err == "" def test_main_file_1(capsys, tmp_path): - testfile1 = tmp_path / 'list1.cmake' - with testfile1.open('w') as fp: - fp.write(' a()') + testfile1 = tmp_path / "list1.cmake" + with testfile1.open("w") as fp: + fp.write(" a()") main([str(testfile1)]) captured = capsys.readouterr() - assert captured.out == 'a()\n' - assert captured.err == '' + assert captured.out == "a()\n" + assert captured.err == "" def test_main_file_2(capsys, tmp_path): - testfile1 = tmp_path / 'list1.cmake' - with testfile1.open('w') as fp: - fp.write(' a()') - testfile2 = tmp_path / 'list2.cmake' - with testfile2.open('w') as fp: - fp.write(' b()') + testfile1 = tmp_path / "list1.cmake" + with testfile1.open("w") as fp: + fp.write(" a()") + testfile2 = tmp_path / "list2.cmake" + with testfile2.open("w") as fp: + fp.write(" b()") main([str(testfile1), str(testfile2)]) captured = capsys.readouterr() - assert captured.out == 'a()\nb()\n' - assert captured.err == '' + assert captured.out == "a()\nb()\n" + assert captured.err == "" def test_main_inplace(capsys, tmp_path): - testfile1 = tmp_path / 'list1.cmake' - with testfile1.open('w') as fp: - fp.write(' a()') + testfile1 = tmp_path / "list1.cmake" + with testfile1.open("w") as fp: + fp.write(" a()") - main(['-i', str(testfile1)]) + main(["-i", str(testfile1)]) captured = capsys.readouterr() - assert captured.out == '' - assert captured.err == '' + assert captured.out == "" + assert captured.err == "" with testfile1.open() as fp: content = fp.read() - assert content == 'a()\n' + assert content == "a()\n" def test_main_diff(capsys, tmp_path): - testfile1 = tmp_path / 'list1.cmake' - with testfile1.open('w') as fp: - fp.write(' a()') + testfile1 = tmp_path / "list1.cmake" + with testfile1.open("w") as fp: + fp.write(" a()") - main(['-d', str(testfile1)]) + main(["-d", str(testfile1)]) captured = capsys.readouterr() assert str(testfile1) in captured.out - assert '- a()' in captured.out - assert '+a()' in captured.out - assert captured.err == '' + assert "- a()" in captured.out + assert "+a()" in captured.out + assert captured.err == "" diff --git a/tests/test_parser.py b/tests/test_parser.py index d8b521c..bd8193a 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -3,9 +3,9 @@ from typing import List from cmake_language_server.parser import ListParser, TokenType -def make_parser_test(liststr: str, - expect_token: List[TokenType], - expect_remain: str = ''): +def make_parser_test( + liststr: str, expect_token: List[TokenType], expect_remain: str = "" +): def test(): actual_token, actual_remain = ListParser().parse(liststr) assert actual_token == expect_token @@ -14,51 +14,70 @@ def make_parser_test(liststr: str, return test -test_command_no_args = make_parser_test('a()', [('a', [])]) -test_command_space = make_parser_test(' a ()', [' ', ('a', [])]) -test_command_arg = make_parser_test('a(b)', [('a', ['b'])]) -test_command_arg_space = make_parser_test('a ( b )', [('a', ['b'])]) -test_command_arg_escape = make_parser_test(r'a(\n\")', [('a', [r'\n\"'])]) -test_command_arg_paren = make_parser_test('a((b))', [('a', ['(', 'b', ')'])]) +test_command_no_args = make_parser_test("a()", [("a", [])]) +test_command_space = make_parser_test(" a ()", [" ", ("a", [])]) +test_command_arg = make_parser_test("a(b)", [("a", ["b"])]) +test_command_arg_space = make_parser_test("a ( b )", [("a", ["b"])]) +test_command_arg_escape = make_parser_test(r"a(\n\")", [("a", [r"\n\""])]) +test_command_arg_paren = make_parser_test("a((b))", [("a", ["(", "b", ")"])]) test_command_arg_paren_paren = make_parser_test( - 'a(((b)))', [('a', ['(', '(', 'b', ')', ')'])]) -test_command_arg_quote = make_parser_test(r'a("b\"")', [('a', [r'"b\""'])]) -test_command_arg_quote_cont = make_parser_test('a("\\\n")', - [('a', ['"\\\n"'])]) -test_command_arg_quo_multiline = make_parser_test('''a("b + "a(((b)))", [("a", ["(", "(", "b", ")", ")"])] +) +test_command_arg_quote = make_parser_test(r'a("b\"")', [("a", [r'"b\""'])]) +test_command_arg_quote_cont = make_parser_test('a("\\\n")', [("a", ['"\\\n"'])]) +test_command_arg_quo_multiline = make_parser_test( + """a("b c -")''', [('a', ['"b\nc\n"'])]) -test_command_arg_bracket_0 = make_parser_test('a([[b]])', [('a', ['[[b]]'])]) -test_command_arg_bracket_1 = make_parser_test('a([=[b]=])', - [('a', ['[=[b]=]'])]) -test_command_arg_space = make_parser_test('a ( b )', [('a', [' ', 'b', ' '])]) -test_command_arg_multi = make_parser_test('a(b c)', [('a', ['b', ' ', 'c'])]) -test_command_multielement = make_parser_test('''a( +")""", + [("a", ['"b\nc\n"'])], +) +test_command_arg_bracket_0 = make_parser_test("a([[b]])", [("a", ["[[b]]"])]) +test_command_arg_bracket_1 = make_parser_test("a([=[b]=])", [("a", ["[=[b]=]"])]) +test_command_arg_space = make_parser_test("a ( b )", [("a", [" ", "b", " "])]) +test_command_arg_multi = make_parser_test("a(b c)", [("a", ["b", " ", "c"])]) +test_command_multielement = make_parser_test( + """a( b c # c -)''', [('a', ['\n', ' ', 'b', '\n', ' ', 'c', ' ', '# c', '\n'])]) -test_line_comment = make_parser_test('a() # b # c', - [('a', []), ' ', '# b # c']) -test_bracket_comment = make_parser_test('#[[a]]#[[b]]', ['#[[a]]', '#[[b]]']) -test_bracket_comment_nested = make_parser_test('#[=[[[a]]]=]', - ['#[=[[[a]]]=]']) -test_bracket_comment_multiline = make_parser_test('#[[\na\nb\nc\n]]', - ['#[[\na\nb\nc\n]]']) -test_if_block = make_parser_test('''if() +)""", + [("a", ["\n", " ", "b", "\n", " ", "c", " ", "# c", "\n"])], +) +test_line_comment = make_parser_test("a() # b # c", [("a", []), " ", "# b # c"]) +test_bracket_comment = make_parser_test("#[[a]]#[[b]]", ["#[[a]]", "#[[b]]"]) +test_bracket_comment_nested = make_parser_test("#[=[[[a]]]=]", ["#[=[[[a]]]=]"]) +test_bracket_comment_multiline = make_parser_test( + "#[[\na\nb\nc\n]]", ["#[[\na\nb\nc\n]]"] +) +test_if_block = make_parser_test( + """if() a() else() b() -endif()''', [('if', []), '\n', ' ', ('a', []), '\n', ('else', []), '\n', ' ', - ('b', []), '\n', ('endif', [])]) +endif()""", + [ + ("if", []), + "\n", + " ", + ("a", []), + "\n", + ("else", []), + "\n", + " ", + ("b", []), + "\n", + ("endif", []), + ], +) test_comment_multi_linecomment = make_parser_test( - '''a()# a + """a()# a b() # b -c() # c''', [('a', []), '# a', '\n', ('b', []), ' ', '# b', '\n', - ('c', []), ' ', '# c']) +c() # c""", + [("a", []), "# a", "\n", ("b", []), " ", "# b", "\n", ("c", []), " ", "# c"], +) -test_incomplete_id = make_parser_test('a', [], 'a') -test_incomplete_command = make_parser_test('a(', [], 'a(') -test_incomplete_id_after_command = make_parser_test('a()\nb', - [('a', []), '\n'], 'b') +test_incomplete_id = make_parser_test("a", [], "a") +test_incomplete_command = make_parser_test("a(", [], "a(") +test_incomplete_id_after_command = make_parser_test("a()\nb", [("a", []), "\n"], "b") test_incomplete_command_after_command = make_parser_test( - 'a()\nb(c', [('a', []), '\n'], 'b(c') + "a()\nb(c", [("a", []), "\n"], "b(c" +) diff --git a/tests/test_server.py b/tests/test_server.py index c0777f5..ad94552 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -2,14 +2,27 @@ from concurrent import futures from pathlib import Path from typing import Optional -from pygls.features import (COMPLETION, FORMATTING, HOVER, INITIALIZE, - TEXT_DOCUMENT_DID_OPEN) +from pygls.features import ( + COMPLETION, + FORMATTING, + HOVER, + INITIALIZE, + TEXT_DOCUMENT_DID_OPEN, +) from pygls.server import LanguageServer -from pygls.types import (CompletionContext, CompletionParams, - CompletionTriggerKind, DidOpenTextDocumentParams, - DocumentFormattingParams, FormattingOptions, - InitializeParams, Position, TextDocumentIdentifier, - TextDocumentItem, TextDocumentPositionParams) +from pygls.types import ( + CompletionContext, + CompletionParams, + CompletionTriggerKind, + DidOpenTextDocumentParams, + DocumentFormattingParams, + FormattingOptions, + InitializeParams, + Position, + TextDocumentIdentifier, + TextDocumentItem, + TextDocumentPositionParams, +) CALL_TIMEOUT = 2 @@ -21,8 +34,9 @@ def _init(client: LanguageServer, root: Path): client.lsp.send_request( INITIALIZE, InitializeParams( - process_id=1234, root_uri=root.as_uri(), - capabilities=None)).result(timeout=CALL_TIMEOUT) + process_id=1234, root_uri=root.as_uri(), capabilities=None + ), + ).result(timeout=CALL_TIMEOUT) except futures.TimeoutError: retry -= 1 else: @@ -36,23 +50,24 @@ def _open(client: LanguageServer, path: Path, text: Optional[str] = None): client.lsp.notify( TEXT_DOCUMENT_DID_OPEN, - DidOpenTextDocumentParams( - TextDocumentItem(path.as_uri(), 'cmake', 1, text))) + DidOpenTextDocumentParams(TextDocumentItem(path.as_uri(), "cmake", 1, text)), + ) -def _test_completion(client_server, datadir, content: str, - context: Optional[CompletionContext]): +def _test_completion( + client_server, datadir, content: str, context: Optional[CompletionContext] +): client, server = client_server _init(client, datadir) - path = datadir / 'CMakeLists.txt' + path = datadir / "CMakeLists.txt" _open(client, path, content) - params = CompletionParams(TextDocumentIdentifier(path.as_uri()), - Position(0, len(content)), context) + params = CompletionParams( + TextDocumentIdentifier(path.as_uri()), Position(0, len(content)), context + ) if context is None: # some clients do not send context del params.context - return client.lsp.send_request(COMPLETION, - params).result(timeout=CALL_TIMEOUT) + return client.lsp.send_request(COMPLETION, params).result(timeout=CALL_TIMEOUT) def test_initialize(client_server, datadir): @@ -65,72 +80,83 @@ def test_initialize(client_server, datadir): def test_completions_invoked(client_server, datadir): response = _test_completion( - client_server, datadir, 'projec', - CompletionContext(CompletionTriggerKind.Invoked)) - item = next(filter(lambda x: x.label == 'project', response.items), None) + client_server, + datadir, + "projec", + CompletionContext(CompletionTriggerKind.Invoked), + ) + item = next(filter(lambda x: x.label == "project", response.items), None) assert item is not None - assert '' in item.documentation + assert "" in item.documentation def test_completions_nocontext(client_server, datadir): - response = _test_completion(client_server, datadir, 'projec', None) - item = next(filter(lambda x: x.label == 'project', response.items), None) + response = _test_completion(client_server, datadir, "projec", None) + item = next(filter(lambda x: x.label == "project", response.items), None) assert item is not None - assert '' in item.documentation + assert "" in item.documentation def test_completions_triggercharacter_variable(client_server, datadir): response = _test_completion( - client_server, datadir, '${', - CompletionContext(CompletionTriggerKind.TriggerCharacter, '{')) - assert 'PROJECT_VERSION' in [x.label for x in response.items] + client_server, + datadir, + "${", + CompletionContext(CompletionTriggerKind.TriggerCharacter, "{"), + ) + assert "PROJECT_VERSION" in [x.label for x in response.items] - response_nocontext = _test_completion(client_server, datadir, '${', None) + response_nocontext = _test_completion(client_server, datadir, "${", None) assert response == response_nocontext def test_completions_triggercharacter_module(client_server, datadir): response = _test_completion( - client_server, datadir, 'include(', - CompletionContext(CompletionTriggerKind.TriggerCharacter, '(')) - assert 'GoogleTest' in [x.label for x in response.items] + client_server, + datadir, + "include(", + CompletionContext(CompletionTriggerKind.TriggerCharacter, "("), + ) + assert "GoogleTest" in [x.label for x in response.items] - response_nocontext = _test_completion(client_server, datadir, 'include(', - None) + response_nocontext = _test_completion(client_server, datadir, "include(", None) assert response == response_nocontext def test_completions_triggercharacter_package(client_server, datadir): response = _test_completion( - client_server, datadir, 'find_package(', - CompletionContext(CompletionTriggerKind.TriggerCharacter, '(')) - assert 'Boost' in [x.label for x in response.items] + client_server, + datadir, + "find_package(", + CompletionContext(CompletionTriggerKind.TriggerCharacter, "("), + ) + assert "Boost" in [x.label for x in response.items] - response_nocontext = _test_completion(client_server, datadir, - 'find_package(', None) + response_nocontext = _test_completion(client_server, datadir, "find_package(", None) assert response == response_nocontext def test_formatting(client_server, datadir): client, server = client_server _init(client, datadir) - path = datadir / 'CMakeLists.txt' - _open(client, path, 'a ( b c ) ') + path = datadir / "CMakeLists.txt" + _open(client, path, "a ( b c ) ") response = client.lsp.send_request( FORMATTING, - DocumentFormattingParams(TextDocumentIdentifier(path.as_uri()), - FormattingOptions( - 2, True))).result(timeout=CALL_TIMEOUT) - assert response[0].newText == 'a(b c)\n' + DocumentFormattingParams( + TextDocumentIdentifier(path.as_uri()), FormattingOptions(2, True) + ), + ).result(timeout=CALL_TIMEOUT) + assert response[0].newText == "a(b c)\n" def test_hover(client_server, datadir): client, server = client_server _init(client, datadir) - path = datadir / 'CMakeLists.txt' - _open(client, path, 'project()') + path = datadir / "CMakeLists.txt" + _open(client, path, "project()") response = client.lsp.send_request( HOVER, - TextDocumentPositionParams(TextDocumentIdentifier(path.as_uri()), - Position())).result(timeout=CALL_TIMEOUT) - assert '' in response.contents.value + TextDocumentPositionParams(TextDocumentIdentifier(path.as_uri()), Position()), + ).result(timeout=CALL_TIMEOUT) + assert "" in response.contents.value diff --git a/tox.ini b/tox.ini index ea9eb0a..12d61bc 100644 --- a/tox.ini +++ b/tox.ini @@ -1,3 +1,15 @@ +[isort] +multi_line_output = 3 +include_trailing_comma = True +force_grid_wrap = 0 +use_parentheses = True +ensure_newline_before_comments = True +line_length = 88 + +[flake8] +max-line-length = 88 +extend-ignore = E203, W503 + [tox] isolated_build = True skipsdist = True @@ -21,6 +33,6 @@ commands = [testenv:lint] commands = poetry run isort -c -rc src tests - poetry run yapf -d -r src tests + poetry run black --diff src tests poetry run flake8 src tests poetry run mypy src tests