diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2020-02-03 11:09:36 +0000 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2020-02-03 11:09:36 +0000 |
commit | 3ff7cff482eac9b6175f88ec956e665079fddfba (patch) | |
tree | ed7dc09fe4cfda5f5ca15e24f89210339dceccdd /app-vim/youcompleteme | |
parent | Remove old ycm, stablize current (diff) | |
download | portage-3ff7cff482eac9b6175f88ec956e665079fddfba.tar.bz2 portage-3ff7cff482eac9b6175f88ec956e665079fddfba.tar.xz portage-3ff7cff482eac9b6175f88ec956e665079fddfba.zip |
Bump youcompleteme
Diffstat (limited to 'app-vim/youcompleteme')
-rw-r--r-- | app-vim/youcompleteme/Manifest | 6 | ||||
-rw-r--r-- | app-vim/youcompleteme/files/remove-python2-support.patch | 5309 | ||||
-rw-r--r-- | app-vim/youcompleteme/youcompleteme-20200203.ebuild | 109 |
3 files changed, 5424 insertions, 0 deletions
diff --git a/app-vim/youcompleteme/Manifest b/app-vim/youcompleteme/Manifest index 99287ab..fa8b856 100644 --- a/app-vim/youcompleteme/Manifest +++ b/app-vim/youcompleteme/Manifest @@ -1,7 +1,13 @@ +AUX remove-python2-support.patch 199204 BLAKE2B 570bd01ae3e8a89c367194329f09738748a64b88b958dc085f91ff42a3a2f1751194905658c8b1d7ff5362869280952d9fec3ed022a0377a2399422e9b25fd70 SHA512 afccbce17d4f5a6605e11c4af65f2f3f89fd70aa689cfd9bfa4aceb08414f0b66ba822d362183499dda42f35996ebc15b478d8bdb348de21a1ad8ccb4651592d DIST gocode-416643789f088aa5077f667cecde7f966131f6be.tar.gz 93109 BLAKE2B c40db19594e7876ab86ab3e67a51d985b9fbd7f38e578f7ccc1bfd4d23dc45d5875d4421aebeaa61851b49ba0cc1f522f18bcdf7438ffae841acddba51620163 SHA512 6dfbed0b47843b6251c86c13b3d6cd741c7745d32c39129cb4ba0e1aa8696d9ddb7bc60c4a1a20092764f89ff5fcde58327612486da8322930d5c0d2a7984765 +DIST gocode-5bee97b488366fd20b054d0861b89834ff5bbfb2.tar.gz 97152 BLAKE2B 4d5e4e6c2cc46348def3cc7700c47f73ac678ce31671d41d4ce37942477a66a65160a2c9d4fb4c6431d46ed2937d67290a6e6565e73b973862da431cbb281ba7 SHA512 9b1e81635a0b168d6e242afb69c47ec95ea9ccca3b039f54193591e9ea2bf09c914765bbf989adfa0ac55e3aab4007eae5fcee8ab28fe695ef87be71a884a4d6 DIST omnisharp-server-e1902915c6790bcec00b8d551199c8a3537d33c9.tar.gz 3005049 BLAKE2B 07c7a06c3d2b75a6df7b6bc6e2e26dc1dbab1af1e98018db14177a82304eb48160bb4dd25f0d6d1af5a50725e6d1b8365932a5ff575d2c08be87997f2ee58397 SHA512 47b6083016d9865708b3deaf44f3742f276d5aa13c3a310b9aa432650df18d35bed62668a90f1aba52fbe84fb7471dd885c34e351b859607d7221ae074290fde DIST python-frozendict-b27053e4d11f5891319fd29eda561c130ba3112a.tar.gz 2192 BLAKE2B 58518ec7185c29d04448552e0dda147ad59c857c1e29f6384dab9a65c030678c6f350f7930f5878094e4fed03e4670df81be3bcb17f9233b55d8d51769621048 SHA512 f943e17e9ad5de31c1c8971e26a45cd61e972cbca31ce26e03285070728364e27edab4549532128a51bbcae38a5166ce8ea6e700069d242b0971f8004fb280f4 +DIST requests-futures-148451a06781d8196e5fb7e0e2bca7a765368ff1.tar.gz 7823 BLAKE2B 6ae2d74849f99a44a449caff70f065d8548d773224b39da661edb880a4eb84aa97da62bd72178b8713cb58ec5deb599fa7eb371fe90669fafc1e42611ada31d1 SHA512 396b02c202f0aa748df02afd8d04b72a2426932e55dde599a82fe134aa585b105267299899c12577f82d43479c56b95d257476010b8d7808817705c1e94a1781 DIST requests-futures-98712e7d0f6be2a090b6fda2a925f85e63656b58.tar.gz 4550 BLAKE2B 8ac1b79dd283ea99093eeaa693a10afddf5ce877263f848b6bb11f2ddd0984937b95f368007efb885ac5cd262aecba5c93c194a48d19283df14a0bdae90a9b46 SHA512 38f0c86ab8f74f4f48a6b4279c5d83580f5486a59b71d4d7009835e3f4e8fcbe07e188d0920de9b223d7c88592998c93e6c66f8aae19d22cf4a31705e066e54c DIST ycmd-4dfa50eb5873c071b446f25b17cbad066164b339.tar.gz 4550802 BLAKE2B de11b0cbb7618971f013ad9bfc425db43f955e8489b8c75c08abbedcb93da8faeb75afbfcc29b84b6238e2da2ec5775198083d03a9867a79d76b0dcdaccba155 SHA512 6233940eacf7592f7164b833f93a784bc39dd8a467e4df08b1433a63bebc405b63b41a1e534dfefd24b5a06faf0e5cdc52467b4cb87d475fd24d66d15c12c770 +DIST ycmd-d3378ca3a3103535c14b104cb916dcbcdaf93eeb.tar.gz 4504015 BLAKE2B f79a3616c9ea2789cd10dd7e1d2b60d651c1f592b213cc0806f92ba12a115ddb3408ac7565e9e486c827ee87a8d4518c55a029f73d518749d3cfa0cd01cd5f00 SHA512 c4af6810995262a5c145ca8eeed9bf92c6ac204ac507f27571b68ed3258affae5734b5edfccdc6ae5f7fa310e1dbf9f74f2681d9c6d774685469ee314ada2573 +DIST youcompleteme-124661f218e80b96c1f9f3d124e99f9a2fd2d83b.tar.gz 317144 BLAKE2B 6fc1d421a41e13923dd677deeabda9b5350c526558acae53d1e38eba4f911ba8d99c28f9b60fcbadd36452fdf985e1c01d456d14ffdb6e86c4bd3fcf38567939 SHA512 7442ad4b72f7782f055ae9ed9e94221a579448f3aaf7054246218e50ab0b19a4f451239a0c67e3c59c27e6e9d8a005273d8524f1acc8f1f855eb14c1b0731078 DIST youcompleteme-25ebc0b9abb1b135c809ee850085a0305cbc5533.tar.gz 291574 BLAKE2B 99f03166cf6c5192e63c307b8c5558589ea877df74a595694f3169982b0ae2939d24fac469e80b476e23d99bf800ebc0b2e8795f1cf4b4a1c18bdd21f25e9bdb SHA512 6abf0696fcd9472d33071a890411bc0f19ba939a2c2a9d2a60480404759e19c3fd93d9eaa916dcd6c777bd8f8f0d02efac89efefca6219ea7b34c93555101115 EBUILD youcompleteme-20190321.ebuild 3688 BLAKE2B de7d0893d15b58aab2ce222b139157424d4cdad5058bd0cafb69c7588c25f0ea74def8601e8bc321edc35a27a61b42212055f96a13dabd01d51f2eb289a07fde SHA512 0a61dd4d3478630b79477f0934955b5bf0e80cdbc4407610b9758d05d4857c5b09129d051bce56472809a22d113f2bd9b9c58160e93c590103d65fec1f007437 +EBUILD youcompleteme-20200203.ebuild 3424 BLAKE2B f6987debc135539e7235ae2b30a96f09066d201c53cf6e7c9b56beb348d20fb1ae8ee74700b0ebc5d4ec8276374806192db21f150b4068d841ace2e5e6fca29c SHA512 440de9a627d2a13372e1dff37cd62196e5ebae7eae49a822554ffb08f32c991cead0fa7f7bb020ed3f7a7d2b10232500fca942cb44e8bbf78f91d2b6c32d3253 diff --git a/app-vim/youcompleteme/files/remove-python2-support.patch b/app-vim/youcompleteme/files/remove-python2-support.patch new file mode 100644 index 0000000..08cbb74 --- /dev/null +++ b/app-vim/youcompleteme/files/remove-python2-support.patch @@ -0,0 +1,5309 @@ +From db57ade716d366e92c604b6d385c96c4b8db8a65 Mon Sep 17 00:00:00 2001 +From: Boris Staletic <boris.staletic@gmail.com> +Date: Thu, 21 Nov 2019 12:58:02 +0100 +Subject: [PATCH] Remove python2 support + +--- + README.md | 90 +-- + autoload/youcompleteme.vim | 194 ++--- + azure-pipelines.yml | 13 - + install.sh | 11 +- + plugin/youcompleteme.vim | 8 +- + python/ycm/base.py | 7 - + python/ycm/buffer.py | 9 +- + python/ycm/client/base_request.py | 20 +- + python/ycm/client/command_request.py | 7 - + .../ycm/client/completer_available_request.py | 7 - + python/ycm/client/completion_request.py | 7 - + python/ycm/client/debug_info_request.py | 7 - + python/ycm/client/event_notification.py | 7 - + python/ycm/client/messages_request.py | 7 - + python/ycm/client/omni_completion_request.py | 7 - + python/ycm/client/shutdown_request.py | 7 - + python/ycm/client/signature_help_request.py | 7 - + python/ycm/client/ycmd_keepalive.py | 9 +- + python/ycm/diagnostic_filter.py | 16 +- + python/ycm/diagnostic_interface.py | 18 +- + python/ycm/omni_completer.py | 7 - + python/ycm/paths.py | 28 +- + python/ycm/signature_help.py | 9 +- + python/ycm/syntax_parse.py | 12 +- + python/ycm/tests/__init__.py | 7 - + python/ycm/tests/base_test.py | 11 +- + python/ycm/tests/client/base_request_test.py | 7 - + .../ycm/tests/client/command_request_test.py | 11 +- + .../tests/client/completion_request_test.py | 9 +- + .../tests/client/debug_info_request_test.py | 7 - + .../ycm/tests/client/messages_request_test.py | 8 - + .../client/omni_completion_request_tests.py | 7 - + python/ycm/tests/command_test.py | 7 - + python/ycm/tests/completion_test.py | 9 - + python/ycm/tests/diagnostic_filter_test.py | 7 - + python/ycm/tests/event_notification_test.py | 9 - + python/ycm/tests/mock_utils.py | 11 +- + python/ycm/tests/paths_test.py | 23 +- + python/ycm/tests/postcomplete_test.py | 7 - + python/ycm/tests/signature_help_test.py | 9 - + python/ycm/tests/syntax_parse_test.py | 7 - + python/ycm/tests/test_utils.py | 48 +- + python/ycm/tests/vimsupport_test.py | 12 - + python/ycm/tests/youcompleteme_test.py | 33 +- + python/ycm/unsafe_thread_pool_executor.py | 3 +- + python/ycm/vimsupport.py | 16 +- + python/ycm/youcompleteme.py | 34 +- + test/README.md | 8 +- + test/docker/ci/push | 1 - + test/docker/ci/rebuild | 3 - + test/docker/manual/push | 1 - + test/docker/manual/rebuild | 3 - + third_party/pythonfutures/CHANGES | 44 -- + third_party/pythonfutures/LICENSE | 21 - + .../pythonfutures/concurrent/__init__.py | 3 - + .../concurrent/futures/__init__.py | 18 - + .../pythonfutures/concurrent/futures/_base.py | 574 -------------- + .../concurrent/futures/_compat.py | 101 --- + .../concurrent/futures/process.py | 363 --------- + .../concurrent/futures/thread.py | 138 ---- + third_party/pythonfutures/crawl.py | 74 -- + third_party/pythonfutures/docs/conf.py | 194 ----- + third_party/pythonfutures/docs/index.rst | 345 --------- + third_party/pythonfutures/docs/make.bat | 112 --- + third_party/pythonfutures/futures/__init__.py | 24 - + third_party/pythonfutures/futures/process.py | 1 - + third_party/pythonfutures/futures/thread.py | 1 - + third_party/pythonfutures/primes.py | 50 -- + third_party/pythonfutures/setup.cfg | 6 - + third_party/pythonfutures/setup.py | 33 - + third_party/pythonfutures/test_futures.py | 723 ------------------ + third_party/pythonfutures/tox.ini | 8 - + 75 files changed, 183 insertions(+), 3552 deletions(-) + delete mode 100755 third_party/pythonfutures/CHANGES + delete mode 100755 third_party/pythonfutures/LICENSE + delete mode 100755 third_party/pythonfutures/concurrent/__init__.py + delete mode 100755 third_party/pythonfutures/concurrent/futures/__init__.py + delete mode 100755 third_party/pythonfutures/concurrent/futures/_base.py + delete mode 100755 third_party/pythonfutures/concurrent/futures/_compat.py + delete mode 100755 third_party/pythonfutures/concurrent/futures/process.py + delete mode 100755 third_party/pythonfutures/concurrent/futures/thread.py + delete mode 100755 third_party/pythonfutures/crawl.py + delete mode 100755 third_party/pythonfutures/docs/conf.py + delete mode 100755 third_party/pythonfutures/docs/index.rst + delete mode 100755 third_party/pythonfutures/docs/make.bat + delete mode 100755 third_party/pythonfutures/futures/__init__.py + delete mode 100755 third_party/pythonfutures/futures/process.py + delete mode 100755 third_party/pythonfutures/futures/thread.py + delete mode 100755 third_party/pythonfutures/primes.py + delete mode 100755 third_party/pythonfutures/setup.cfg + delete mode 100755 third_party/pythonfutures/setup.py + delete mode 100755 third_party/pythonfutures/test_futures.py + delete mode 100755 third_party/pythonfutures/tox.ini + +diff --git a/README.md b/README.md +index d296b5ba3..0705acdb2 100644 +--- a/README.md ++++ b/README.md +@@ -281,7 +281,7 @@ YouCompleteMe, however they may not work for everyone. If the following + instructions don't work for you, check out the [full installation + guide](#full-installation-guide). + +-Make sure you have Vim 7.4.1578 with Python 2 or Python 3 support. The Vim ++Make sure you have Vim 7.4.1578 with Python 3 support. The Vim + package on Fedora 27 and later and the pre-installed Vim on Ubuntu 16.04 and + later are recent enough. You can see the version of Vim installed by running + `vim --version`. If the version is too old, you may need to [compile Vim from +@@ -376,13 +376,13 @@ guide](#full-installation-guide). + **Important:** we assume that you are using the `cmd.exe` command prompt and + that you know how to add an executable to the PATH environment variable. + +-Make sure you have at least Vim 7.4.1578 with Python 2 or Python 3 support. You ++Make sure you have at least Vim 7.4.1578 with Python 3 support. You + can check the version and which Python is supported by typing `:version` inside +-Vim. Look at the features included: `+python/dyn` for Python 2 and +-`+python3/dyn` for Python 3. Take note of the Vim architecture, i.e. 32 or ++Vim. Look at the features included: `+python3/dyn` for Python 3. ++Take note of the Vim architecture, i.e. 32 or + 64-bit. It will be important when choosing the Python installer. We recommend + using a 64-bit client. [Daily updated installers of 32-bit and 64-bit Vim with +-Python 2 and Python 3 support][vim-win-download] are available. ++Python 3 support][vim-win-download] are available. + + **NOTE**: For all features, such as signature help, use Vim 8.1.1875 or later. + +@@ -403,17 +403,15 @@ process. + + Download and install the following software: + +-- [Python 2 or Python 3][python-win-download]. Be sure to pick the version ++- [Python 3][python-win-download]. Be sure to pick the version + corresponding to your Vim architecture. It is _Windows x86_ for a 32-bit Vim + and _Windows x86-64_ for a 64-bit Vim. We recommend installing Python 3. + Additionally, the version of Python you install must match up exactly with + the version of Python that Vim is looking for. Type `:version` and look at the + bottom of the page at the list of compiler flags. Look for flags that look +- similar to `-DDYNAMIC_PYTHON_DLL=\"python27.dll\"` and +- `-DDYNAMIC_PYTHON3_DLL=\"python35.dll\"`. The former indicates that Vim is +- looking for Python 2.7 and the latter indicates that Vim is looking for +- Python 3.5. You'll need one or the other installed, matching the version +- number exactly. ++ similar to `-DDYNAMIC_PYTHON3_DLL=\"python35.dll\"`. This indicates ++ that Vim is looking for Python 3.5. You'll need one or the other installed, ++ matching the version number exactly. + - [CMake][cmake-download]. Add CMake executable to the PATH environment + variable. + - [Visual Studio Build Tools 2017][visual-studio-download]. During setup, +@@ -488,7 +486,7 @@ guide](#full-installation-guide). + + **NOTE:** OpenBSD / FreeBSD are not officially supported platforms by YCM. + +-Make sure you have Vim 7.4.1578 with Python 2 or Python 3 support. ++Make sure you have Vim 7.4.1578 with Python 3 support. + + **NOTE**: For all features, such as signature help, use Vim 8.1.1875 or later. + +@@ -588,7 +586,7 @@ process. + **Please follow the instructions carefully. Read EVERY WORD.** + + 1. **Ensure that your version of Vim is _at least_ 7.4.1578 _and_ that it has +- support for Python 2 or Python 3 scripting**. ++ support for Python 3 scripting**. + + Inside Vim, type `:version`. Look at the first two to three lines of output; + it should say `Vi IMproved X.Y`, where X.Y is the major version of vim. If +@@ -654,7 +652,7 @@ process. + Debian-like Linux distro, this would be `sudo apt-get install python-dev + python3-dev`. On macOS they should already be present. + +- On Windows, you need to download and install [Python 2 or ++ On Windows, you need to download and install [Python + Python 3][python-win-download]. Pick the version corresponding to your Vim + architecture. You will also need Microsoft Visual C++ (MSVC) to build YCM. + You can obtain it by installing [Visual Studio Build +@@ -1500,8 +1498,6 @@ should work out of the box with no additional configuration (provided that you + built YCM with the `--rust-completer` flag; see the [*Installation* + section](#installation) for details). The install script takes care of + installing [the Rust source code][rust-src], so no configuration is necessary. +-In case you are running Python 2.7.8 and older, you will need to manually +-install [rustup][]. + + To [configure RLS](#lsp-configuration) look up [rls configuration options][ + rls-preferences] +@@ -3252,34 +3248,6 @@ But fear not, you should be able to tweak your extra conf files to continue + working by using the `g:ycm_extra_conf_vim_data` option. See the docs on that + option for details. + +-### I get `ImportError` exceptions that mention `PyInit_ycm_core` or `initycm_core` +- +-These errors are caused by building the YCM native libraries for Python 2 and +-trying to load them into a Python 3 process (or the other way around). +- +-For instance, if building for Python 2 but loading in Python 3: +- +-``` +-ImportError: dynamic module does not define init function (PyInit_ycm_core) +-``` +- +-If building for Python 3 but loading in Python 2: +- +-``` +-ImportError: dynamic module does not define init function (initycm_core) +-``` +- +-Setting the `g:ycm_server_python_interpreter` option to force the use of a +-specific Python interpreter for `ycmd` is usually the easiest way to solve the +-problem. Common values for that option are `/usr/bin/python` and +-`/usr/bin/python3`. +- +-### I get a linker warning regarding `libpython` on macOS when compiling YCM +- +-If the warning is `ld: warning: path '/usr/lib/libpython2.7.dylib' following -L +-not a directory`, then feel free to ignore it; it's caused by a limitation of +-CMake and is not an issue. Everything should still work fine. +- + ### I get a weird window at the top of my file when I use the semantic engine + + This is Vim's `preview` window. Vim uses it to show you extra information about +@@ -3357,20 +3325,20 @@ Look at the output of your CMake call. There should be a line in it like the + following (with `.dylib` in place of `.so` on macOS): + + ``` +--- Found PythonLibs: /usr/lib/libpython2.7.so (Required is at least version "2.5") ++-- Found PythonLibs: /usr/lib/libpython3.6.so (Required is at least version "3.5") + ``` + + That would be the **correct** output. An example of **incorrect** output would + be the following: + + ``` +--- Found PythonLibs: /usr/lib/libpython2.7.so (found suitable version "2.5.1", minimum required is "2.5") ++-- Found PythonLibs: /usr/lib/libpython3.6.so (found suitable version "3.5.1", minimum required is "3.5") + ``` + + Notice how there's an extra bit of output there, the `found suitable version + "<version>"` part, where `<version>` is not the same as the version of the +-dynamic library. In the example shown, the library is version 2.7 but the second +-string is version `2.5.1`. ++dynamic library. In the example shown, the library is version 3.6 but the second ++string is version `3.5.1`. + + This means that CMake found one version of Python headers and a different + version for the library. This is wrong. It can happen when you have multiple +@@ -3380,7 +3348,7 @@ You should probably add the following flags to your cmake call (again, `dylib` + instead of `so` on macOS): + + ``` +--DPYTHON_INCLUDE_DIR=/usr/include/python2.7 -DPYTHON_LIBRARY=/usr/lib/libpython2.7.so ++-DPYTHON_INCLUDE_DIR=/usr/include/python3.6 -DPYTHON_LIBRARY=/usr/lib/libpython3.6.so + ``` + + This will force the paths to the Python include directory and the Python library +@@ -3388,22 +3356,22 @@ to use. You may need to set these flags to something else, but you need to make + sure you use the same version of Python that your Vim binary is built against, + which is highly likely to be the system's default Python. + +-### I get `libpython2.7.a [...] relocation R_X86_64_32` when compiling ++### I get `libpython3.5.a [...] relocation R_X86_64_32` when compiling + + The error is usually encountered when compiling YCM on Centos or RHEL. The full + error looks something like the following: + + ``` +-/usr/bin/ld: /usr/local/lib/libpython2.7.a(abstract.o): relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC ++/usr/bin/ld: /usr/local/lib/libpython3.5.a(abstract.o): relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC + ``` + + It's possible to get a slightly different error that's similar to the one above. + Here's the problem and how you solve it: + +-Your `libpython2.7.a` was not compiled with `-fPIC` so it can't be linked into ++Your `libpython3.5.a` was not compiled with `-fPIC` so it can't be linked into + `ycm_core.so`. Use the `-DPYTHON_LIBRARY=` CMake flag to point it to a `.so` + version of libpython on your machine (for instance, +-`-DPYTHON_LIBRARY=/usr/lib/libpython2.7.so`). Naturally, this means you'll have ++`-DPYTHON_LIBRARY=/usr/lib/libpython3.5.so`). Naturally, this means you'll have + to go through the full installation guide by hand. + + ### I see `undefined symbol: clang_getCompletionFixIt` in the server logs. +@@ -3640,20 +3608,6 @@ os.environ['PATH'] = ';'.join(path) + EOF + ``` + +-### I hear that YCM only supports Python 2, is that true? +- +-**No.** Both the Vim client and the [ycmd server][ycmd] run on Python 2 or 3. If +-you are talking about code completion in a project, you can configure the Python +-used for your project through a `.ycm_extra_conf.py` file. See [the Python +-Semantic Completion section](#python-semantic-completion) for more details. +- +-### On Windows I get `E887: Sorry, this command is disabled, the Python's site module could not be loaded` +- +-If you are running vim on Windows with Python 2.7.11, this is likely caused by a +-[bug][vim_win-python2.7.11-bug]. Follow this +-[workaround][vim_win-python2.7.11-bug_workaround] or use a different version +-(Python 2.7.12 does not suffer from the bug). +- + ### I can't complete Python packages in a virtual environment. + + This means that the Python used to run [Jedi][] is not the Python of the virtual +@@ -3823,8 +3777,6 @@ This software is licensed under the [GPL v3 license][gpl]. + [add-msbuild-to-path]: http://stackoverflow.com/questions/6319274/how-do-i-run-msbuild-from-the-command-line-using-windows-sdk-7-1 + [identify-R6034-cause]: http://stackoverflow.com/questions/14552348/runtime-error-r6034-in-embedded-python-application/34696022 + [ccoc]: https://github.com/Valloric/YouCompleteMe/blob/master/CODE_OF_CONDUCT.md +-[vim_win-python2.7.11-bug]: https://github.com/vim/vim/issues/717 +-[vim_win-python2.7.11-bug_workaround]: https://github.com/vim/vim-win32-installer/blob/a27bbdba9bb87fa0e44c8a00d33d46be936822dd/appveyor.bat#L86-L88 + [gitter]: https://gitter.im/Valloric/YouCompleteMe + [ninja-compdb]: https://ninja-build.org/manual.html + [++enc]: http://vimdoc.sourceforge.net/htmldoc/editing.html#++enc +diff --git a/autoload/youcompleteme.vim b/autoload/youcompleteme.vim +index d8f4703e5..8e07aa8e7 100644 +--- a/autoload/youcompleteme.vim ++++ b/autoload/youcompleteme.vim +@@ -58,32 +58,6 @@ let s:buftype_blacklist = { + \ } + + +-" When both versions are available, we prefer Python 3 over Python 2: +-" - faster startup (no monkey-patching from python-future); +-" - better Windows support (e.g. temporary paths are not returned in all +-" lowercase); +-" - Python 2 support will eventually be dropped. +-function! s:UsingPython3() +- if has('python3') +- return 1 +- endif +- return 0 +-endfunction +- +- +-let s:using_python3 = s:UsingPython3() +-let s:python_until_eof = s:using_python3 ? "python3 << EOF" : "python << EOF" +-let s:python_command = s:using_python3 ? "py3 " : "py " +- +- +-function! s:Pyeval( eval_string ) +- if s:using_python3 +- return py3eval( a:eval_string ) +- endif +- return pyeval( a:eval_string ) +-endfunction +- +- + function! s:StartMessagePoll() + if s:pollers.receive_messages.id < 0 + let s:pollers.receive_messages.id = timer_start( +@@ -96,10 +70,9 @@ endfunction + function! s:ReceiveMessages( timer_id ) + let poll_again = v:false + if s:AllowedToCompleteInCurrentBuffer() +- let poll_again = s:Pyeval( 'ycm_state.OnPeriodicTick()' ) ++ let poll_again = py3eval( 'ycm_state.OnPeriodicTick()' ) + endif + +- + if poll_again + let s:pollers.receive_messages.id = timer_start( + \ s:pollers.receive_messages.wait_milliseconds, +@@ -164,7 +137,7 @@ function! youcompleteme#Enable() + \ s:pollers.server_ready.wait_milliseconds, + \ function( 's:PollServerReady' ) ) + +- let s:default_completion = s:Pyeval( 'vimsupport.NO_COMPLETIONS' ) ++ let s:default_completion = py3eval( 'vimsupport.NO_COMPLETIONS' ) + let s:completion = s:default_completion + + if exists( '*prop_type_add' ) && exists( '*prop_type_delete' ) +@@ -198,50 +171,24 @@ endfunction + + + function! youcompleteme#GetErrorCount() +- return s:Pyeval( 'ycm_state.GetErrorCount()' ) ++ return py3eval( 'ycm_state.GetErrorCount()' ) + endfunction + + + function! youcompleteme#GetWarningCount() +- return s:Pyeval( 'ycm_state.GetWarningCount()' ) ++ return py3eval( 'ycm_state.GetWarningCount()' ) + endfunction + + + function! s:SetUpPython() abort +- exec s:python_until_eof +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +- ++ py3 << EOF + import os.path as p +-import re + import sys + import traceback + import vim + + root_folder = p.normpath( p.join( vim.eval( 's:script_folder_path' ), '..' ) ) + third_party_folder = p.join( root_folder, 'third_party' ) +-python_stdlib_zip_regex = re.compile( 'python[23][0-9]\\.zip' ) +- +- +-def IsStandardLibraryFolder( path ): +- return ( ( p.isfile( path ) +- and python_stdlib_zip_regex.match( p.basename( path ) ) ) +- or p.isfile( p.join( path, 'os.py' ) ) ) +- +- +-def IsVirtualEnvLibraryFolder( path ): +- return p.isfile( p.join( path, 'orig-prefix.txt' ) ) +- +- +-def GetStandardLibraryIndexInSysPath(): +- for index, path in enumerate( sys.path ): +- if ( IsStandardLibraryFolder( path ) and +- not IsVirtualEnvLibraryFolder( path ) ): +- return index +- raise RuntimeError( 'Could not find standard library path in Python path.' ) +- + + # Add dependencies to Python path. + dependencies = [ p.join( root_folder, 'python' ), +@@ -256,18 +203,10 @@ dependencies = [ p.join( root_folder, 'python' ), + p.join( third_party_folder, 'requests_deps', 'certifi' ), + p.join( third_party_folder, 'requests_deps', 'requests' ) ] + +-# The concurrent.futures module is part of the standard library on Python 3. +-if sys.version_info[ 0 ] == 2: +- dependencies.append( p.join( third_party_folder, 'pythonfutures' ) ) +- + sys.path[ 0:0 ] = dependencies + + # We enclose this code in a try/except block to avoid backtraces in Vim. + try: +- # The python-future module must be inserted after the standard library path. +- sys.path.insert( GetStandardLibraryIndexInSysPath() + 1, +- p.join( third_party_folder, 'python-future', 'src' ) ) +- + # Import the modules used in this file. + from ycm import base, vimsupport, youcompleteme + +@@ -315,14 +254,12 @@ function! s:SetUpKeyMappings() + " With this command, when the completion window is visible, the tab key + " (default) will select the next candidate in the window. In vim, this also + " changes the typed-in text to that of the candidate completion. +- exe 'inoremap <expr>' . key . +- \ ' pumvisible() ? "\<C-n>" : "\' . key .'"' ++ exe 'inoremap <expr>' . key . ' pumvisible() ? "\<C-n>" : "\' . key .'"' + endfor + + for key in g:ycm_key_list_previous_completion + " This selects the previous candidate for shift-tab (default) +- exe 'inoremap <expr>' . key . +- \ ' pumvisible() ? "\<C-p>" : "\' . key .'"' ++ exe 'inoremap <expr>' . key . ' pumvisible() ? "\<C-p>" : "\' . key .'"' + endfor + + for key in g:ycm_key_list_stop_completion +@@ -387,10 +324,12 @@ function! s:SetUpSigns() + highlight link YcmWarningLine SyntasticWarningLine + endif + +- exe 'sign define YcmError text=' . g:ycm_error_symbol . +- \ ' texthl=YcmErrorSign linehl=YcmErrorLine' +- exe 'sign define YcmWarning text=' . g:ycm_warning_symbol . +- \ ' texthl=YcmWarningSign linehl=YcmWarningLine' ++ call sign_define( 'YcmError', { 'text': g:ycm_error_symbol, ++ \ 'texthl': 'YcmErrorSign', ++ \ 'linehl': 'YcmErrorLine' } ) ++ call sign_define( 'YcmWarning', { 'text': g:ycm_error_symbol, ++ \ 'texthl': 'YcmWarningSign', ++ \ 'linehl': 'YcmWarningLine' } ) + endfunction + + +@@ -451,9 +390,8 @@ function! s:DisableOnLargeFile( buffer ) + let b:ycm_largefile = + \ threshold > 0 && getfsize( expand( a:buffer ) ) > threshold + if b:ycm_largefile +- exec s:python_command "vimsupport.PostVimMessage(" . +- \ "'YouCompleteMe is disabled in this buffer; " . +- \ "the file exceeded the max size (see YCM options).' )" ++ py3 vimsupport.PostVimMessage( 'YouCompleteMe is disabled in this buffer;' . ++ \ ' the file exceeded the max size (see YCM options).' ) + endif + return b:ycm_largefile + endfunction +@@ -560,7 +498,7 @@ function! s:OnVimLeave() + for poller in values( s:pollers ) + call s:StopPoller( poller ) + endfor +- exec s:python_command "ycm_state.OnVimLeave()" ++ py3 ycm_state.OnVimLeave() + endfunction + + +@@ -569,7 +507,7 @@ function! s:OnCompleteDone() + return + endif + +- exec s:python_command "ycm_state.OnCompleteDone()" ++ py3 ycm_state.OnCompleteDone() + call s:UpdateSignatureHelp() + endfunction + +@@ -599,7 +537,7 @@ function! s:OnFileTypeSet() + call s:SetCompleteFunc() + call s:StartMessagePoll() + +- exec s:python_command "ycm_state.OnFileTypeSet()" ++ py3 ycm_state.OnFileTypeSet() + call s:OnFileReadyToParse( 1 ) + endfunction + +@@ -613,7 +551,7 @@ function! s:OnBufferEnter() + call s:SetUpCompleteopt() + call s:SetCompleteFunc() + +- exec s:python_command "ycm_state.OnBufferVisit()" ++ py3 ycm_state.OnBufferVisit() + " Last parse may be outdated because of changes from other buffers. Force a + " new parse. + call s:OnFileReadyToParse( 1 ) +@@ -628,23 +566,23 @@ function! s:OnBufferUnload() + return + endif + +- exec s:python_command "ycm_state.OnBufferUnload( " . buffer_number . " )" ++ py3 ycm_state.OnBufferUnload( vimsupport.GetIntValue( 'buffer_number' ) ) + endfunction + + + function! s:UpdateMatches() +- exec s:python_command "ycm_state.UpdateMatches()" ++ py3 ycm_state.UpdateMatches() + endfunction + + + function! s:PollServerReady( timer_id ) +- if !s:Pyeval( 'ycm_state.IsServerAlive()' ) +- exec s:python_command "ycm_state.NotifyUserIfServerCrashed()" ++ if !py3eval( 'ycm_state.IsServerAlive()' ) ++ py3 ycm_state.NotifyUserIfServerCrashed() + " Server crashed. Don't poll it again. + return + endif + +- if !s:Pyeval( 'ycm_state.CheckIfServerIsReady()' ) ++ if !py3eval( 'ycm_state.CheckIfServerIsReady()' ) + let s:pollers.server_ready.id = timer_start( + \ s:pollers.server_ready.wait_milliseconds, + \ function( 's:PollServerReady' ) ) +@@ -663,11 +601,11 @@ function! s:OnFileReadyToParse( ... ) + + " We only want to send a new FileReadyToParse event notification if the buffer + " has changed since the last time we sent one, or if forced. +- if force_parsing || s:Pyeval( "ycm_state.NeedsReparse()" ) ++ if force_parsing || py3eval( "ycm_state.NeedsReparse()" ) + " We switched buffers or somethuing, so claer. + " FIXME: sig hekp should be buffer local? + call s:ClearSignatureHelp() +- exec s:python_command "ycm_state.OnFileReadyToParse()" ++ py3 ycm_state.OnFileReadyToParse() + + call s:StopPoller( s:pollers.file_parse_response ) + let s:pollers.file_parse_response.id = timer_start( +@@ -678,15 +616,15 @@ endfunction + + + function! s:PollFileParseResponse( ... ) +- if !s:Pyeval( "ycm_state.FileParseRequestReady()" ) ++ if !py3eval( "ycm_state.FileParseRequestReady()" ) + let s:pollers.file_parse_response.id = timer_start( + \ s:pollers.file_parse_response.wait_milliseconds, + \ function( 's:PollFileParseResponse' ) ) + return + endif + +- exec s:python_command "ycm_state.HandleFileParseRequest()" +- if s:Pyeval( "ycm_state.ShouldResendFileParseRequest()" ) ++ py3 ycm_state.HandleFileParseRequest() ++ if py3eval( "ycm_state.ShouldResendFileParseRequest()" ) + call s:OnFileReadyToParse( 1 ) + endif + endfunction +@@ -755,7 +693,7 @@ function! s:OnCursorMovedNormalMode() + return + endif + +- exec s:python_command "ycm_state.OnCursorMoved()" ++ py3 ycm_state.OnCursorMoved() + endfunction + + +@@ -784,7 +722,7 @@ function! s:OnTextChangedInsertMode() + " We have to make sure we correctly leave semantic mode even when the user + " inserts something like a "operator[]" candidate string which fails + " CurrentIdentifierFinished check. +- if s:force_semantic && !s:Pyeval( 'base.LastEnteredCharIsIdentifierChar()' ) ++ if s:force_semantic && !py3eval( 'base.LastEnteredCharIsIdentifierChar()' ) + let s:force_semantic = 0 + endif + +@@ -800,7 +738,7 @@ function! s:OnTextChangedInsertMode() + call s:RequestSignatureHelp() + endif + +- exec s:python_command "ycm_state.OnCursorMoved()" ++ py3 ycm_state.OnCursorMoved() + + if g:ycm_autoclose_preview_window_after_completion + call s:ClosePreviewWindowIfNeeded() +@@ -818,7 +756,7 @@ function! s:OnInsertLeave() + let s:completion = s:default_completion + + call s:OnFileReadyToParse() +- exec s:python_command "ycm_state.OnInsertLeave()" ++ py3 ycm_state.OnInsertLeave() + if g:ycm_autoclose_preview_window_after_completion || + \ g:ycm_autoclose_preview_window_after_insertion + call s:ClosePreviewWindowIfNeeded() +@@ -845,10 +783,10 @@ endfunction + + + function! s:IdentifierFinishedOperations() +- if !s:Pyeval( 'base.CurrentIdentifierFinished()' ) ++ if !py3eval( 'base.CurrentIdentifierFinished()' ) + return + endif +- exec s:python_command "ycm_state.OnCurrentIdentifierFinished()" ++ py3 ycm_state.OnCurrentIdentifierFinished() + let s:force_semantic = 0 + let s:completion = s:default_completion + endfunction +@@ -888,13 +826,13 @@ endfunction + + + function! s:OnBlankLine() +- return s:Pyeval( 'not vim.current.line or vim.current.line.isspace()' ) ++ return py3eval( 'not vim.current.line or vim.current.line.isspace()' ) + endfunction + + + function! s:RequestCompletion() +- exec s:python_command "ycm_state.SendCompletionRequest(" . +- \ "vimsupport.GetBoolValue( 's:force_semantic' ) )" ++ py3 ycm_state.SendCompletionRequest( ++ \ vimsupport.GetBoolValue( 's:force_semantic' ) ) + + call s:PollCompletion() + endfunction +@@ -903,7 +841,7 @@ endfunction + function! s:RequestSemanticCompletion() + if &completefunc == "youcompleteme#CompleteFunc" + let s:force_semantic = 1 +- exec s:python_command "ycm_state.SendCompletionRequest( True )" ++ py3 ycm_state.SendCompletionRequest( True ) + + call s:PollCompletion() + endif +@@ -916,20 +854,20 @@ endfunction + + + function! s:PollCompletion( ... ) +- if !s:Pyeval( 'ycm_state.CompletionRequestReady()' ) ++ if !py3eval( 'ycm_state.CompletionRequestReady()' ) + let s:pollers.completion.id = timer_start( + \ s:pollers.completion.wait_milliseconds, + \ function( 's:PollCompletion' ) ) + return + endif + +- let s:completion = s:Pyeval( 'ycm_state.GetCompletionResponse()' ) ++ let s:completion = py3eval( 'ycm_state.GetCompletionResponse()' ) + call s:Complete() + endfunction + + + function! s:ShouldUseSignatureHelp() +- return s:Pyeval( 'vimsupport.VimSupportsPopupWindows()' ) ++ return py3eval( 'vimsupport.VimSupportsPopupWindows()' ) + endfunction + + +@@ -943,7 +881,7 @@ function! s:RequestSignatureHelp() + return + endif + +- if s:Pyeval( 'ycm_state.SendSignatureHelpRequest()' ) ++ if py3eval( 'ycm_state.SendSignatureHelpRequest()' ) + call s:PollSignatureHelp() + endif + endfunction +@@ -960,14 +898,14 @@ function! s:PollSignatureHelp( ... ) + return + endif + +- if !s:Pyeval( 'ycm_state.SignatureHelpRequestReady()' ) ++ if !py3eval( 'ycm_state.SignatureHelpRequestReady()' ) + let s:pollers.signature_help.id = timer_start( + \ s:pollers.signature_help.wait_milliseconds, + \ function( 's:PollSignatureHelp' ) ) + return + endif + +- let s:signature_help = s:Pyeval( 'ycm_state.GetSignatureHelpResponse()' ) ++ let s:signature_help = py3eval( 'ycm_state.GetSignatureHelpResponse()' ) + call s:UpdateSignatureHelp() + endfunction + +@@ -1023,7 +961,7 @@ function! s:UpdateSignatureHelp() + return + endif + +- call s:Pyeval( ++ call py3eval( + \ 'ycm_state.UpdateSignatureHelp( vim.eval( "s:signature_help" ) )' ) + endfunction + +@@ -1035,12 +973,12 @@ function! s:ClearSignatureHelp() + + call s:StopPoller( s:pollers.signature_help ) + let s:signature_help = s:default_signature_help +- call s:Pyeval( 'ycm_state.ClearSignatureHelp()' ) ++ call py3eval( 'ycm_state.ClearSignatureHelp()' ) + endfunction + + + function! youcompleteme#ServerPid() +- return s:Pyeval( 'ycm_state.ServerPid()' ) ++ return py3eval( 'ycm_state.ServerPid()' ) + endfunction + + +@@ -1049,7 +987,7 @@ function! s:SetUpCommands() + command! YcmDebugInfo call s:DebugInfo() + command! -nargs=* -complete=custom,youcompleteme#LogsComplete + \ YcmToggleLogs call s:ToggleLogs(<f-args>) +- if s:Pyeval( 'vimsupport.VimVersionAtLeast( "7.4.1898" )' ) ++ if py3eval( 'vimsupport.VimVersionAtLeast( "7.4.1898" )' ) + command! -nargs=* -complete=custom,youcompleteme#SubCommandsComplete -range + \ YcmCompleter call s:CompleterCommand(<q-mods>, + \ <count>, +@@ -1073,7 +1011,7 @@ endfunction + function! s:RestartServer() + call s:SetUpOptions() + +- exec s:python_command "ycm_state.RestartServer()" ++ py3 ycm_state.RestartServer() + + call s:StopPoller( s:pollers.receive_messages ) + call s:ClearSignatureHelp() +@@ -1087,7 +1025,7 @@ endfunction + + function! s:DebugInfo() + echom "Printing YouCompleteMe debug information..." +- let debug_info = s:Pyeval( 'ycm_state.DebugInfo()' ) ++ let debug_info = py3eval( 'ycm_state.DebugInfo()' ) + for line in split( debug_info, "\n" ) + echom '-- ' . line + endfor +@@ -1095,50 +1033,50 @@ endfunction + + + function! s:ToggleLogs(...) +- exec s:python_command "ycm_state.ToggleLogs( *vim.eval( 'a:000' ) )" ++ py3 ycm_state.ToggleLogs( *vim.eval( 'a:000' ) ) + endfunction + + + function! youcompleteme#LogsComplete( arglead, cmdline, cursorpos ) +- return join( s:Pyeval( 'list( ycm_state.GetLogfiles() )' ), "\n" ) ++ return join( py3eval( 'list( ycm_state.GetLogfiles() )' ), "\n" ) + endfunction + + + function! s:CompleterCommand( mods, count, line1, line2, ... ) +- exec s:python_command "ycm_state.SendCommandRequest(" . +- \ "vim.eval( 'a:000' )," . +- \ "vim.eval( 'a:mods' )," . +- \ "vimsupport.GetBoolValue( 'a:count != -1' )," . +- \ "vimsupport.GetIntValue( 'a:line1' )," . +- \ "vimsupport.GetIntValue( 'a:line2' ) )" ++ py3 ycm_state.SendCommandRequest( ++ \ vim.eval( 'a:000' ), ++ \ vim.eval( 'a:mods' ), ++ \ vimsupport.GetBoolValue( 'a:count != -1' ), ++ \ vimsupport.GetIntValue( 'a:line1' ), ++ \ vimsupport.GetIntValue( 'a:line2' ) ) + endfunction + + + function! youcompleteme#SubCommandsComplete( arglead, cmdline, cursorpos ) +- return join( s:Pyeval( 'ycm_state.GetDefinedSubcommands()' ), "\n" ) ++ return join( py3eval( 'ycm_state.GetDefinedSubcommands()' ), "\n" ) + endfunction + + + function! youcompleteme#OpenGoToList() +- exec s:python_command "vimsupport.PostVimMessage(" . ++ py3 vimsupport.PostVimMessage( + \ "'WARNING: youcompleteme#OpenGoToList function is deprecated. " . +- \ "Do NOT use it.' )" +- exec s:python_command "vimsupport.OpenQuickFixList( True, True )" ++ \ "Do NOT use it.'" ) ++ py3 vimsupport.OpenQuickFixList( True, True ) + endfunction + + + function! s:ShowDiagnostics() +- exec s:python_command "ycm_state.ShowDiagnostics()" ++ py3 ycm_state.ShowDiagnostics() + endfunction + + + function! s:ShowDetailedDiagnostic() +- exec s:python_command "ycm_state.ShowDetailedDiagnostic()" ++ py3 ycm_state.ShowDetailedDiagnostic() + endfunction + + + function! s:ForceCompileAndDiagnostics() +- exec s:python_command "ycm_state.ForceCompileAndDiagnostics()" ++ py3 ycm_state.ForceCompileAndDiagnostics() + endfunction + + +diff --git a/azure-pipelines.yml b/azure-pipelines.yml +index c23f2a62d..3b43a69c4 100644 +--- a/azure-pipelines.yml ++++ b/azure-pipelines.yml +@@ -18,10 +18,6 @@ jobs: + vmImage: 'ubuntu-16.04' + strategy: + matrix: +- 'Python 2.7': +- # Tests are failing on Python 2.7.0 with the exception +- # "TypeError: argument can't be <type 'unicode'>" +- YCM_PYTHON_VERSION: '2.7.13' + 'Python 3.5': + YCM_PYTHON_VERSION: '3.5.3' + maxParallel: 2 +@@ -49,9 +45,6 @@ jobs: + vmImage: 'ubuntu-16.04' + strategy: + matrix: +- 'Python 2.7': +- IMAGE: ycm-vim-py2 +- PIP: pip + 'Python 3.5': + IMAGE: ycm-vim-py3 + PIP: pip3 +@@ -82,8 +75,6 @@ jobs: + vmImage: 'macOS-10.13' + strategy: + matrix: +- 'Python 2.7': +- YCM_PYTHON_VERSION: '2.7.13' + 'Python 3.5': + YCM_PYTHON_VERSION: '3.5.3' + maxParallel: 2 +@@ -109,10 +100,6 @@ jobs: + vmImage: 'windows-2019' + strategy: + matrix: +- # We only test Python 2.7 on 64-bit. +- 'Python 2.7 64-bit': +- YCM_PYTHON_VERSION: '2.7' +- YCM_ARCH: x64 + 'Python 3.7 32-bit': + YCM_PYTHON_VERSION: '3.7' + YCM_ARCH: x86 +diff --git a/install.sh b/install.sh +index 8c9c2fd1b..82ecf88c1 100755 +--- a/install.sh ++++ b/install.sh +@@ -5,13 +5,4 @@ echo "WARNING: this script is deprecated. Use the install.py script instead." 1> + + SCRIPT_DIR=$(dirname $0 || exit $?) + +-command_exists() { +- command -v "$1" >/dev/null 2>&1 ; +-} +- +-PYTHON_BINARY=python +-if command_exists python2; then +- PYTHON_BINARY=python2 +-fi +- +-$PYTHON_BINARY "$SCRIPT_DIR/install.py" "$@" || exit $? ++python3 "$SCRIPT_DIR/install.py" "$@" || exit $? +diff --git a/plugin/youcompleteme.vim b/plugin/youcompleteme.vim +index d2994c25a..bfe77516a 100644 +--- a/plugin/youcompleteme.vim ++++ b/plugin/youcompleteme.vim +@@ -55,17 +55,17 @@ elseif !has( 'timers' ) + call s:restore_cpo() + finish + elseif ( v:version > 800 || ( v:version == 800 && has( 'patch1436' ) ) ) && +- \ !has( 'python_compiled' ) && !has( 'python3_compiled' ) ++ \ !has( 'python3_compiled' ) + echohl WarningMsg | + \ echomsg "YouCompleteMe unavailable: requires Vim compiled with " . +- \ "Python (2.7.1+ or 3.5.1+) support." | ++ \ "Python (3.5.1+) support." | + \ echohl None + call s:restore_cpo() + finish +-" These calls try to load the Python 2 and Python 3 libraries when Vim is ++" These calls try to load the Python 3 libraries when Vim is + " compiled dynamically against them. Since only one can be loaded at a time on + " some platforms, we first check if Python 3 is available. +-elseif !has( 'python3' ) && !has( 'python' ) ++elseif !has( 'python3' ) + echohl WarningMsg | + \ echomsg "YouCompleteMe unavailable: unable to load Python." | + \ echohl None +diff --git a/python/ycm/base.py b/python/ycm/base.py +index 7013dfed1..2d331c618 100644 +--- a/python/ycm/base.py ++++ b/python/ycm/base.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm import vimsupport + from ycmd import identifier_utils + +diff --git a/python/ycm/buffer.py b/python/ycm/buffer.py +index b95c0da32..848adc898 100644 +--- a/python/ycm/buffer.py ++++ b/python/ycm/buffer.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm import vimsupport + from ycm.client.event_notification import EventNotification + from ycm.diagnostic_interface import DiagnosticInterface +@@ -34,7 +27,7 @@ + # Used to store buffer related information like diagnostics, latest parse + # request. Stores buffer change tick at the parse request moment, allowing + # to effectively determine whether reparse is needed for the buffer. +-class Buffer( object ): ++class Buffer: + + def __init__( self, bufnr, user_options, filetypes ): + self._number = bufnr +diff --git a/python/ycm/client/base_request.py b/python/ycm/client/base_request.py +index ec7d5ecea..e474fc54f 100644 +--- a/python/ycm/client/base_request.py ++++ b/python/ycm/client/base_request.py +@@ -15,21 +15,15 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + import logging + import json + import vim +-from future.utils import native + from base64 import b64decode, b64encode ++from hmac import compare_digest ++from urllib.parse import urljoin, urlparse + from ycm import vimsupport +-from ycmd.utils import ToBytes, urljoin, urlparse, GetCurrentDirectory +-from ycmd.hmac_utils import CreateRequestHmac, CreateHmac, SecureBytesEqual ++from ycmd.utils import ToBytes, GetCurrentDirectory ++from ycmd.hmac_utils import CreateRequestHmac, CreateHmac + from ycmd.responses import ServerError, UnknownExtraConf + + _HEADERS = { 'content-type': 'application/json' } +@@ -40,7 +34,7 @@ + _logger = logging.getLogger( __name__ ) + + +-class BaseRequest( object ): ++class BaseRequest: + + def __init__( self ): + self._should_resend = False +@@ -298,13 +292,13 @@ def _ToUtf8Json( data ): + def _ValidateResponseObject( response ): + our_hmac = CreateHmac( response.content, BaseRequest.hmac_secret ) + their_hmac = ToBytes( b64decode( response.headers[ _HMAC_HEADER ] ) ) +- if not SecureBytesEqual( our_hmac, their_hmac ): ++ if not compare_digest( our_hmac, their_hmac ): + raise RuntimeError( 'Received invalid HMAC for response!' ) + return True + + + def _BuildUri( handler ): +- return native( ToBytes( urljoin( BaseRequest.server_location, handler ) ) ) ++ return ToBytes( urljoin( BaseRequest.server_location, handler ) ) + + + def MakeServerException( data ): +diff --git a/python/ycm/client/command_request.py b/python/ycm/client/command_request.py +index 168af18dd..ac25304e9 100644 +--- a/python/ycm/client/command_request.py ++++ b/python/ycm/client/command_request.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.client.base_request import BaseRequest, BuildRequestData + from ycm import vimsupport + from ycmd.utils import ToUnicode +diff --git a/python/ycm/client/completer_available_request.py b/python/ycm/client/completer_available_request.py +index 9ee9dd3f8..7822876fc 100644 +--- a/python/ycm/client/completer_available_request.py ++++ b/python/ycm/client/completer_available_request.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.client.base_request import BaseRequest, BuildRequestData + + +diff --git a/python/ycm/client/completion_request.py b/python/ycm/client/completion_request.py +index fa7cd223a..8e0b72771 100644 +--- a/python/ycm/client/completion_request.py ++++ b/python/ycm/client/completion_request.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + import logging + from ycmd.utils import ToUnicode + from ycm.client.base_request import ( BaseRequest, DisplayServerException, +diff --git a/python/ycm/client/debug_info_request.py b/python/ycm/client/debug_info_request.py +index 32d7bd3df..95949086b 100644 +--- a/python/ycm/client/debug_info_request.py ++++ b/python/ycm/client/debug_info_request.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.client.base_request import BaseRequest, BuildRequestData + + +diff --git a/python/ycm/client/event_notification.py b/python/ycm/client/event_notification.py +index bdbe07e34..eee90eefe 100644 +--- a/python/ycm/client/event_notification.py ++++ b/python/ycm/client/event_notification.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.client.base_request import BaseRequest, BuildRequestData + + +diff --git a/python/ycm/client/messages_request.py b/python/ycm/client/messages_request.py +index 0f1bd2aab..d382d1445 100644 +--- a/python/ycm/client/messages_request.py ++++ b/python/ycm/client/messages_request.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.client.base_request import BaseRequest, BuildRequestData + from ycm.vimsupport import PostVimMessage + +diff --git a/python/ycm/client/omni_completion_request.py b/python/ycm/client/omni_completion_request.py +index 397ba2128..3733603b1 100644 +--- a/python/ycm/client/omni_completion_request.py ++++ b/python/ycm/client/omni_completion_request.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.client.completion_request import CompletionRequest + + +diff --git a/python/ycm/client/shutdown_request.py b/python/ycm/client/shutdown_request.py +index ae42734fb..159814315 100644 +--- a/python/ycm/client/shutdown_request.py ++++ b/python/ycm/client/shutdown_request.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.client.base_request import BaseRequest + + TIMEOUT_SECONDS = 0.1 +diff --git a/python/ycm/client/signature_help_request.py b/python/ycm/client/signature_help_request.py +index 292b3407c..f65c47d39 100644 +--- a/python/ycm/client/signature_help_request.py ++++ b/python/ycm/client/signature_help_request.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + import logging + from ycm.client.base_request import ( BaseRequest, DisplayServerException, + MakeServerException ) +diff --git a/python/ycm/client/ycmd_keepalive.py b/python/ycm/client/ycmd_keepalive.py +index 278ef86ea..a13727f73 100644 +--- a/python/ycm/client/ycmd_keepalive.py ++++ b/python/ycm/client/ycmd_keepalive.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + import time + from threading import Thread + from ycm.client.base_request import BaseRequest +@@ -30,7 +23,7 @@ + # This class can be used to keep the ycmd server alive for the duration of the + # life of the client. By default, ycmd shuts down if it doesn't see a request in + # a while. +-class YcmdKeepalive( object ): ++class YcmdKeepalive: + def __init__( self, ping_interval_seconds = 60 * 10 ): + self._keepalive_thread = Thread( target = self._ThreadMain ) + self._keepalive_thread.daemon = True +diff --git a/python/ycm/diagnostic_filter.py b/python/ycm/diagnostic_filter.py +index 7448f2c0a..eb651df48 100644 +--- a/python/ycm/diagnostic_filter.py ++++ b/python/ycm/diagnostic_filter.py +@@ -15,19 +15,11 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- +-from future.utils import iterkeys, iteritems + from ycm import vimsupport + import re + + +-class DiagnosticFilter( object ): ++class DiagnosticFilter: + def __init__( self, config_or_filters ): + if isinstance( config_or_filters, list ): + self._filters = config_or_filters +@@ -55,7 +47,7 @@ def SubsetForTypes( self, filetypes ): + def CreateFromOptions( user_options ): + all_filters = user_options[ 'filter_diagnostics' ] + compiled_by_type = {} +- for type_spec, filter_value in iteritems( all_filters ): ++ for type_spec, filter_value in all_filters.items(): + filetypes = [ type_spec ] + if type_spec.find( ',' ) != -1: + filetypes = type_spec.split( ',' ) +@@ -65,7 +57,7 @@ def CreateFromOptions( user_options ): + return _MasterDiagnosticFilter( compiled_by_type ) + + +-class _MasterDiagnosticFilter( object ): ++class _MasterDiagnosticFilter: + + def __init__( self, all_filters ): + self._all_filters = all_filters +@@ -139,7 +131,7 @@ def _CompileFilters( config ): + """Given a filter config dictionary, return a list of compiled filters""" + filters = [] + +- for filter_type in iterkeys( config ): ++ for filter_type in config.keys(): + compiler = FILTER_COMPILERS.get( filter_type ) + + if compiler is not None: +diff --git a/python/ycm/diagnostic_interface.py b/python/ycm/diagnostic_interface.py +index 5475d961a..3e4d8f99b 100644 +--- a/python/ycm/diagnostic_interface.py ++++ b/python/ycm/diagnostic_interface.py +@@ -15,20 +15,12 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- +-from future.utils import itervalues, iteritems + from collections import defaultdict + from ycm import vimsupport + from ycm.diagnostic_filter import DiagnosticFilter, CompileLevel + + +-class DiagnosticInterface( object ): ++class DiagnosticInterface: + def __init__( self, bufnr, user_options ): + self._bufnr = bufnr + self._user_options = user_options +@@ -114,7 +106,7 @@ def _EchoDiagnosticForLine( self, line_num ): + + def _DiagnosticsCount( self, predicate ): + count = 0 +- for diags in itervalues( self._line_to_diags ): ++ for diags in self._line_to_diags.values(): + count += sum( 1 for d in diags if predicate( d ) ) + return count + +@@ -136,7 +128,7 @@ def UpdateMatches( self ): + + matches_to_remove = vimsupport.GetDiagnosticMatchesInCurrentWindow() + +- for diags in itervalues( self._line_to_diags ): ++ for diags in self._line_to_diags.values(): + # Insert squiggles in reverse order so that errors overlap warnings. + for diag in reversed( diags ): + group = ( 'YcmErrorSection' if _DiagnosticIsError( diag ) else +@@ -157,7 +149,7 @@ def UpdateMatches( self ): + def _UpdateSigns( self ): + signs_to_unplace = vimsupport.GetSignsInBuffer( self._bufnr ) + +- for line, diags in iteritems( self._line_to_diags ): ++ for line, diags in self._line_to_diags.items(): + if not diags: + continue + +@@ -185,7 +177,7 @@ def _ConvertDiagListToDict( self ): + line_number = location[ 'line_num' ] + self._line_to_diags[ line_number ].append( diag ) + +- for diags in itervalues( self._line_to_diags ): ++ for diags in self._line_to_diags.values(): + # We also want errors to be listed before warnings so that errors aren't + # hidden by the warnings; Vim won't place a sign over an existing one. + diags.sort( key = lambda diag: ( diag[ 'kind' ], +diff --git a/python/ycm/omni_completer.py b/python/ycm/omni_completer.py +index a62a968b3..8c9f6a0fc 100644 +--- a/python/ycm/omni_completer.py ++++ b/python/ycm/omni_completer.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + import vim + from ycm import vimsupport + from ycmd import utils +diff --git a/python/ycm/paths.py b/python/ycm/paths.py +index 013a66e30..055c9d90a 100644 +--- a/python/ycm/paths.py ++++ b/python/ycm/paths.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + import os + import sys + import vim +@@ -33,7 +26,7 @@ + 'ycmd' ) + WIN_PYTHON_PATH = os.path.join( sys.exec_prefix, 'python.exe' ) + PYTHON_BINARY_REGEX = re.compile( +- r'python((2(\.7)?)|(3(\.[5-9])?))?(.exe)?$', re.IGNORECASE ) ++ r'python(3(\.[5-9])?)?(.exe)?$', re.IGNORECASE ) + + + # Not caching the result of this function; users shouldn't have to restart Vim +@@ -51,7 +44,7 @@ def PathToPythonInterpreter(): + return python_interpreter + + raise RuntimeError( "Path in 'g:ycm_server_python_interpreter' option " +- "does not point to a valid Python 2.7 or 3.5+." ) ++ "does not point to a valid Python 3.5+." ) + + python_interpreter = _PathToPythonUsedDuringBuild() + if python_interpreter and utils.GetExecutable( python_interpreter ): +@@ -66,18 +59,12 @@ def PathToPythonInterpreter(): + if _EndsWithPython( python_interpreter ): + return python_interpreter + +- # As a last resort, we search python in the PATH. We prefer Python 2 over 3 +- # for the sake of backwards compatibility with ycm_extra_conf.py files out +- # there; few people wrote theirs to work on py3. +- # So we check 'python2' before 'python' because on some distributions (Arch +- # Linux for example), python refers to python3. +- python_interpreter = utils.PathToFirstExistingExecutable( [ 'python2', +- 'python', +- 'python3' ] ) ++ python_interpreter = utils.PathToFirstExistingExecutable( [ 'python3', ++ 'python' ] ) + if python_interpreter: + return python_interpreter + +- raise RuntimeError( "Cannot find Python 2.7 or 3.5+. " ++ raise RuntimeError( "Cannot find Python 3.5+. " + "Set the 'g:ycm_server_python_interpreter' option " + "to a Python interpreter path." ) + +@@ -88,13 +75,12 @@ def _PathToPythonUsedDuringBuild(): + try: + filepath = os.path.join( DIR_OF_YCMD, 'PYTHON_USED_DURING_BUILDING' ) + return utils.ReadFile( filepath ).strip() +- # We need to check for IOError for Python2 and OSError for Python3 +- except ( IOError, OSError ): ++ except OSError: + return None + + + def _EndsWithPython( path ): +- """Check if given path ends with a python 2.7 or 3.5+ name.""" ++ """Check if given path ends with a python 3.5+ name.""" + return path and PYTHON_BINARY_REGEX.search( path ) is not None + + +diff --git a/python/ycm/signature_help.py b/python/ycm/signature_help.py +index 821aa4350..0fd6dd3a7 100644 +--- a/python/ycm/signature_help.py ++++ b/python/ycm/signature_help.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + import vim + import json + from ycm import vimsupport +@@ -29,7 +22,7 @@ + from ycm.vimsupport import memoize, GetIntValue + + +-class SignatureHelpState( object ): ++class SignatureHelpState: + ACTIVE = 'ACTIVE' + INACTIVE = 'INACTIVE' + +diff --git a/python/ycm/syntax_parse.py b/python/ycm/syntax_parse.py +index 0fbdad9d0..aa44eb5e0 100644 +--- a/python/ycm/syntax_parse.py ++++ b/python/ycm/syntax_parse.py +@@ -15,14 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- +-from future.utils import itervalues + import re + from ycm import vimsupport + +@@ -61,7 +53,7 @@ + } + + +-class SyntaxGroup( object ): ++class SyntaxGroup: + def __init__( self, name, lines = None ): + self.name = name + self.lines = lines if lines else [] +@@ -169,7 +161,7 @@ def GetParentNames( group ): + parent_names.append( line[ len( links_to ): ] ) + return parent_names + +- for group in itervalues( group_name_to_group ): ++ for group in group_name_to_group.values(): + parent_names = GetParentNames( group ) + + for parent_name in parent_names: +diff --git a/python/ycm/tests/__init__.py b/python/ycm/tests/__init__.py +index 5ee0f8c8a..ad542f791 100644 +--- a/python/ycm/tests/__init__.py ++++ b/python/ycm/tests/__init__.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.tests.test_utils import MockVimModule + MockVimModule() + +diff --git a/python/ycm/tests/base_test.py b/python/ycm/tests/base_test.py +index 15e51b2ce..53473165c 100644 +--- a/python/ycm/tests/base_test.py ++++ b/python/ycm/tests/base_test.py +@@ -1,7 +1,5 @@ +-# coding: utf-8 +-# + # Copyright (C) 2013 Google Inc. +-# 2016 YouCompleteMe contributors ++# 2020 YouCompleteMe contributors + # + # This file is part of YouCompleteMe. + # +@@ -18,13 +16,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + import contextlib + from nose.tools import eq_, ok_ + from mock import patch +diff --git a/python/ycm/tests/client/base_request_test.py b/python/ycm/tests/client/base_request_test.py +index 997313a0c..29ddc8bf0 100644 +--- a/python/ycm/tests/client/base_request_test.py ++++ b/python/ycm/tests/client/base_request_test.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.tests.test_utils import MockVimBuffers, MockVimModule, VimBuffer + MockVimModule() + +diff --git a/python/ycm/tests/client/command_request_test.py b/python/ycm/tests/client/command_request_test.py +index ac5f83ee6..fc4b3f4ce 100644 +--- a/python/ycm/tests/client/command_request_test.py ++++ b/python/ycm/tests/client/command_request_test.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.tests.test_utils import ExtendedMock, MockVimModule + MockVimModule() + +@@ -31,7 +24,7 @@ + from ycm.client.command_request import CommandRequest + + +-class GoToResponse_QuickFix_test( object ): ++class GoToResponse_QuickFix_test: + """This class tests the generation of QuickFix lists for GoTo responses which + return multiple locations, such as the Python completer and JavaScript + completer. It mostly proves that we use 1-based indexing for the column +@@ -118,7 +111,7 @@ def _CheckGoToList( self, + set_fitting_height.assert_called_once_with() + + +-class Response_Detection_test( object ): ++class Response_Detection_test: + + def BasicResponse_test( self ): + def _BasicResponseTest( command, response ): +diff --git a/python/ycm/tests/client/completion_request_test.py b/python/ycm/tests/client/completion_request_test.py +index a39e4499f..ef7cdd3c2 100644 +--- a/python/ycm/tests/client/completion_request_test.py ++++ b/python/ycm/tests/client/completion_request_test.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from nose.tools import eq_ + from ycm.tests.test_utils import MockVimModule + vim_mock = MockVimModule() +@@ -29,7 +22,7 @@ + from ycm.client import completion_request + + +-class ConvertCompletionResponseToVimDatas_test( object ): ++class ConvertCompletionResponseToVimDatas_test: + """ This class tests the + completion_request._ConvertCompletionResponseToVimDatas method """ + +diff --git a/python/ycm/tests/client/debug_info_request_test.py b/python/ycm/tests/client/debug_info_request_test.py +index 9ce2a4331..93f7ac393 100644 +--- a/python/ycm/tests/client/debug_info_request_test.py ++++ b/python/ycm/tests/client/debug_info_request_test.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from copy import deepcopy + from hamcrest import assert_that, contains_string, equal_to + +diff --git a/python/ycm/tests/client/messages_request_test.py b/python/ycm/tests/client/messages_request_test.py +index 1f89f7170..2504ca074 100644 +--- a/python/ycm/tests/client/messages_request_test.py ++++ b/python/ycm/tests/client/messages_request_test.py +@@ -15,14 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +- +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.tests.test_utils import MockVimModule + MockVimModule() + +diff --git a/python/ycm/tests/client/omni_completion_request_tests.py b/python/ycm/tests/client/omni_completion_request_tests.py +index 39c267b4b..0028ee3f7 100644 +--- a/python/ycm/tests/client/omni_completion_request_tests.py ++++ b/python/ycm/tests/client/omni_completion_request_tests.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from mock import MagicMock + from nose.tools import eq_ + +diff --git a/python/ycm/tests/command_test.py b/python/ycm/tests/command_test.py +index 0652207b8..f4e909db1 100644 +--- a/python/ycm/tests/command_test.py ++++ b/python/ycm/tests/command_test.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.tests.test_utils import MockVimModule, MockVimBuffers, VimBuffer + MockVimModule() + +diff --git a/python/ycm/tests/completion_test.py b/python/ycm/tests/completion_test.py +index 00ac7cf38..db9c972da 100644 +--- a/python/ycm/tests/completion_test.py ++++ b/python/ycm/tests/completion_test.py +@@ -1,5 +1,3 @@ +-# coding: utf-8 +-# + # Copyright (C) 2016 YouCompleteMe contributors + # + # This file is part of YouCompleteMe. +@@ -17,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.tests.test_utils import ( CurrentWorkingDirectory, ExtendedMock, + MockVimModule, MockVimBuffers, VimBuffer ) + MockVimModule() +diff --git a/python/ycm/tests/diagnostic_filter_test.py b/python/ycm/tests/diagnostic_filter_test.py +index e4a74b227..3591feb93 100644 +--- a/python/ycm/tests/diagnostic_filter_test.py ++++ b/python/ycm/tests/diagnostic_filter_test.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.tests.test_utils import MockVimModule + MockVimModule() + +diff --git a/python/ycm/tests/event_notification_test.py b/python/ycm/tests/event_notification_test.py +index ce1450ae0..85e73dcb4 100644 +--- a/python/ycm/tests/event_notification_test.py ++++ b/python/ycm/tests/event_notification_test.py +@@ -1,5 +1,3 @@ +-# coding: utf-8 +-# + # Copyright (C) 2015-2018 YouCompleteMe contributors + # + # This file is part of YouCompleteMe. +@@ -17,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.tests.test_utils import ( CurrentWorkingDirectory, ExtendedMock, + MockVimBuffers, MockVimModule, VimBuffer, + VimSign ) +diff --git a/python/ycm/tests/mock_utils.py b/python/ycm/tests/mock_utils.py +index 3770202de..36faa10a0 100644 +--- a/python/ycm/tests/mock_utils.py ++++ b/python/ycm/tests/mock_utils.py +@@ -14,18 +14,11 @@ + # + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + import mock + import requests + + +-class FakeResponse( object ): ++class FakeResponse: + """A fake version of a requests response object, just about suitable for + mocking a server response. Not usually used directly. See + MockServerResponse* methods""" +@@ -46,7 +39,7 @@ def raise_for_status( self ): + raise self._exception + + +-class FakeFuture( object ): ++class FakeFuture: + """A fake version of a future response object, just about suitable for + mocking a server response as generated by PostDataToHandlerAsync. + Not usually used directly. See MockAsyncServerResponse* methods""" +diff --git a/python/ycm/tests/paths_test.py b/python/ycm/tests/paths_test.py +index 1bd4390ed..86c7c8069 100644 +--- a/python/ycm/tests/paths_test.py ++++ b/python/ycm/tests/paths_test.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.tests.test_utils import MockVimModule + MockVimModule() + +@@ -39,20 +32,6 @@ def EndsWithPython_Bad( path ): + 'Path {0} does end with a Python name.'.format( path ) ) + + +-def EndsWithPython_Python2Paths_test(): +- python_paths = [ +- 'python', +- 'python2', +- '/usr/bin/python2.7', +- '/home/user/.pyenv/shims/python2.7', +- r'C:\Python27\python.exe', +- '/Contents/MacOS/Python' +- ] +- +- for path in python_paths: +- yield EndsWithPython_Good, path +- +- + def EndsWithPython_Python3Paths_test(): + python_paths = [ + 'python3', +@@ -71,7 +50,7 @@ def EndsWithPython_BadPaths_test(): + '', + '/opt/local/bin/vim', + r'C:\Program Files\Vim\vim74\gvim.exe', +- '/usr/bin/python2.5', ++ '/usr/bin/python2.7', + '/home/user/.pyenv/shims/python3.2', + ] + +diff --git a/python/ycm/tests/postcomplete_test.py b/python/ycm/tests/postcomplete_test.py +index e1ee26230..bccf95739 100644 +--- a/python/ycm/tests/postcomplete_test.py ++++ b/python/ycm/tests/postcomplete_test.py +@@ -17,13 +17,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.tests.test_utils import MockVimModule + MockVimModule() + +diff --git a/python/ycm/tests/signature_help_test.py b/python/ycm/tests/signature_help_test.py +index d46c5fc16..f993376ab 100644 +--- a/python/ycm/tests/signature_help_test.py ++++ b/python/ycm/tests/signature_help_test.py +@@ -1,5 +1,3 @@ +-# coding: utf-8 +-# + # Copyright (C) 2019 YouCompleteMe contributors + # + # This file is part of YouCompleteMe. +@@ -17,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-# Intentionally not importing unicode_literals! +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from hamcrest import ( assert_that, + empty ) + from ycm import signature_help as sh +diff --git a/python/ycm/tests/syntax_parse_test.py b/python/ycm/tests/syntax_parse_test.py +index 7c6566339..a807cd7ad 100644 +--- a/python/ycm/tests/syntax_parse_test.py ++++ b/python/ycm/tests/syntax_parse_test.py +@@ -16,13 +16,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.tests.test_utils import MockVimModule + MockVimModule() + +diff --git a/python/ycm/tests/test_utils.py b/python/ycm/tests/test_utils.py +index 1f076d05d..fc4349fe2 100644 +--- a/python/ycm/tests/test_utils.py ++++ b/python/ycm/tests/test_utils.py +@@ -15,15 +15,7 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from collections import defaultdict, namedtuple +-from future.utils import iteritems, PY2 + from mock import DEFAULT, MagicMock, patch + from hamcrest import assert_that, equal_to + import contextlib +@@ -39,7 +31,7 @@ + except ImportError: + from unittest2 import skipIf + +-from ycmd.utils import GetCurrentDirectory, OnMac, OnWindows, ToBytes, ToUnicode ++from ycmd.utils import GetCurrentDirectory, OnMac, OnWindows, ToUnicode + + + BUFNR_REGEX = re.compile( '^bufnr\\(\'(?P<buffer_filename>.+)\', ([01])\\)$' ) +@@ -180,8 +172,7 @@ def _MockVimBufferEval( value ): + if match: + findstart = int( match.group( 'findstart' ) ) + base = match.group( 'base' ) +- value = current_buffer.omnifunc( findstart, base ) +- return value if findstart else ToBytesOnPY2( value ) ++ return current_buffer.omnifunc( findstart, base ) + + return None + +@@ -201,7 +192,7 @@ def _MockVimOptionsEval( value ): + + if value == 'keys( g: )': + global_options = {} +- for key, value in iteritems( VIM_OPTIONS ): ++ for key, value in VIM_OPTIONS.items(): + if key.startswith( 'g:' ): + global_options[ key[ 2: ] ] = value + return global_options +@@ -382,7 +373,7 @@ def _MockVimCommand( command ): + return DEFAULT + + +-class VimBuffer( object ): ++class VimBuffer: + """An object that looks like a vim.buffer object: + - |name| : full path of the buffer with symbolic links resolved; + - |number| : buffer number; +@@ -457,7 +448,7 @@ def __repr__( self ): + self.number ) + + +-class VimBuffers( object ): ++class VimBuffers: + """An object that looks like a vim.buffers object.""" + + def __init__( self, buffers ): +@@ -482,7 +473,7 @@ def pop( self, index ): + return self._buffers.pop( index ) + + +-class VimWindow( object ): ++class VimWindow: + """An object that looks like a vim.window object: + - |number|: number of the window; + - |buffer_object|: a VimBuffer object representing the buffer inside the +@@ -503,7 +494,7 @@ def __repr__( self ): + self.cursor ) + + +-class VimWindows( object ): ++class VimWindows: + """An object that looks like a vim.windows object.""" + + def __init__( self, buffers, cursor ): +@@ -530,7 +521,7 @@ def __iter__( self ): + return iter( self._windows ) + + +-class VimCurrent( object ): ++class VimCurrent: + """An object that looks like a vim.current object. |current_window| must be a + VimWindow object.""" + +@@ -540,7 +531,7 @@ def __init__( self, current_window ): + self.line = self.buffer.contents[ current_window.cursor[ 0 ] - 1 ] + + +-class VimMatch( object ): ++class VimMatch: + + def __init__( self, group, pattern ): + current_window = VIM_MOCK.current.window.number +@@ -565,7 +556,7 @@ def __getitem__( self, key ): + return self.id + + +-class VimSign( object ): ++class VimSign: + + def __init__( self, sign_id, line, name, bufnr ): + self.id = sign_id +@@ -717,22 +708,3 @@ def Wrapper( *args, **kwargs ): + return Wrapper + + return decorator +- +- +-def ToBytesOnPY2( data ): +- # To test the omnifunc, etc. returning strings, which can be of different +- # types depending on python version, we use ToBytes on PY2 and just the native +- # str on python3. This roughly matches what happens between py2 and py3 +- # versions within Vim. +- if not PY2: +- return data +- +- if isinstance( data, int ): +- return data +- if isinstance( data, list ): +- return [ ToBytesOnPY2( item ) for item in data ] +- if isinstance( data, dict ): +- for item in data: +- data[ item ] = ToBytesOnPY2( data[ item ] ) +- return data +- return ToBytes( data ) +diff --git a/python/ycm/tests/vimsupport_test.py b/python/ycm/tests/vimsupport_test.py +index ea9e006c5..bb79aef26 100644 +--- a/python/ycm/tests/vimsupport_test.py ++++ b/python/ycm/tests/vimsupport_test.py +@@ -1,5 +1,3 @@ +-# coding: utf-8 +-# + # Copyright (C) 2015-2018 YouCompleteMe contributors + # + # This file is part of YouCompleteMe. +@@ -16,14 +14,6 @@ + # + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. +- +-# Intentionally not importing unicode_literals! +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.tests import PathToTestFile + from ycm.tests.test_utils import ( CurrentWorkingDirectory, ExtendedMock, + MockVimBuffers, MockVimModule, Version, +@@ -1705,8 +1695,6 @@ def InsertNamespace_append_test( vim_current, *args ): + + @patch( 'vim.command', new_callable = ExtendedMock ) + def JumpToLocation_SameFile_SameBuffer_NoSwapFile_test( vim_command ): +- # No 'u' prefix for the current buffer name string to simulate Vim returning +- # bytes on Python 2 but unicode on Python 3. + current_buffer = VimBuffer( 'uni¢𐍈d€' ) + with MockVimBuffers( [ current_buffer ], [ current_buffer ] ) as vim: + vimsupport.JumpToLocation( os.path.realpath( u'uni¢𐍈d€' ), +diff --git a/python/ycm/tests/youcompleteme_test.py b/python/ycm/tests/youcompleteme_test.py +index 069d4f30f..42a436093 100644 +--- a/python/ycm/tests/youcompleteme_test.py ++++ b/python/ycm/tests/youcompleteme_test.py +@@ -15,13 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- + from ycm.client.messages_request import MessagesPoll + from ycm.tests.test_utils import ( ExtendedMock, + MockVimBuffers, +@@ -71,7 +64,7 @@ def YouCompleteMe_InvalidPythonInterpreterPath_test( post_vim_message ): + post_vim_message.assert_called_once_with( + "Unable to start the ycmd server. " + "Path in 'g:ycm_server_python_interpreter' option does not point " +- "to a valid Python 2.7 or 3.5+. " ++ "to a valid Python 3.5+. " + "Correct the error then restart the server with ':YcmRestartServer'." ) + + post_vim_message.reset_mock() +@@ -98,7 +91,7 @@ def YouCompleteMe_NoPythonInterpreterFound_test( post_vim_message, *args ): + + assert_that( ycm.IsServerAlive(), equal_to( False ) ) + post_vim_message.assert_called_once_with( +- "Unable to start the ycmd server. Cannot find Python 2.7 or 3.5+. " ++ "Unable to start the ycmd server. Cannot find Python 3.5+. " + "Set the 'g:ycm_server_python_interpreter' option to a Python " + "interpreter path. " + "Correct the error then restart the server with ':YcmRestartServer'." ) +@@ -154,28 +147,6 @@ def YouCompleteMe_NotifyUserIfServerCrashed_MissingCore_test(): + } ) + + +-def YouCompleteMe_NotifyUserIfServerCrashed_Python2Core_test(): +- message = ( "The ycmd server SHUT DOWN (restart with ':YcmRestartServer'). " +- "YCM core library compiled for Python 2 but loaded in Python 3. " +- "Set the 'g:ycm_server_python_interpreter' option to a Python 2 " +- "interpreter path." ) +- RunNotifyUserIfServerCrashed( { +- 'return_code': 5, +- 'expected_message': equal_to( message ) +- } ) +- +- +-def YouCompleteMe_NotifyUserIfServerCrashed_Python3Core_test(): +- message = ( "The ycmd server SHUT DOWN (restart with ':YcmRestartServer'). " +- "YCM core library compiled for Python 3 but loaded in Python 2. " +- "Set the 'g:ycm_server_python_interpreter' option to a Python 3 " +- "interpreter path." ) +- RunNotifyUserIfServerCrashed( { +- 'return_code': 6, +- 'expected_message': equal_to( message ) +- } ) +- +- + def YouCompleteMe_NotifyUserIfServerCrashed_OutdatedCore_test(): + message = ( "The ycmd server SHUT DOWN (restart with ':YcmRestartServer'). " + "YCM core library too old; PLEASE RECOMPILE by running the " +diff --git a/python/ycm/unsafe_thread_pool_executor.py b/python/ycm/unsafe_thread_pool_executor.py +index e55dc018c..5baa11f2d 100644 +--- a/python/ycm/unsafe_thread_pool_executor.py ++++ b/python/ycm/unsafe_thread_pool_executor.py +@@ -6,7 +6,6 @@ + # (the Python Software Foundation License). + + +-from __future__ import with_statement + import threading + import weakref + import sys +@@ -28,7 +27,7 @@ + # only send network requests). The YCM workload is one of those workloads where + # it's safe (the aforementioned network requests case). + +-class _WorkItem( object ): ++class _WorkItem: + def __init__( self, future, fn, args, kwargs ): + self.future = future + self.fn = fn +diff --git a/python/ycm/vimsupport.py b/python/ycm/vimsupport.py +index 81ab12219..93d5b676b 100644 +--- a/python/ycm/vimsupport.py ++++ b/python/ycm/vimsupport.py +@@ -15,14 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- +-from future.utils import iterkeys + import vim + import os + import json +@@ -321,8 +313,7 @@ def GetDiagnosticMatchPattern( line_num, + def LineAndColumnNumbersClamped( line_num, column_num ): + line_num = max( min( line_num, len( vim.current.buffer ) ), 1 ) + +- # Vim buffers are a list of byte objects on Python 2 but Unicode objects on +- # Python 3. ++ # Vim buffers are a list of Unicode objects on Python 3. + max_column = len( ToBytes( vim.current.buffer[ line_num - 1 ] ) ) + + return line_num, min( column_num, max_column ) +@@ -876,7 +867,7 @@ def ReplaceChunks( chunks, silent=False ): + chunks_by_file = _SortChunksByFile( chunks ) + + # We sort the file list simply to enable repeatable testing. +- sorted_file_list = sorted( iterkeys( chunks_by_file ) ) ++ sorted_file_list = sorted( chunks_by_file.keys() ) + + if not silent: + # Make sure the user is prepared to have her screen mutilated by the new +@@ -997,8 +988,7 @@ def ReplaceChunk( start, end, replacement_text, vim_buffer ): + # so we convert to bytes + replacement_lines = SplitLines( ToBytes( replacement_text ) ) + +- # NOTE: Vim buffers are a list of byte objects on Python 2 but unicode +- # objects on Python 3. ++ # NOTE: Vim buffers are a list of unicode objects on Python 3. + start_existing_text = ToBytes( vim_buffer[ start_line ] )[ : start_column ] + end_line_text = ToBytes( vim_buffer[ end_line ] ) + end_existing_text = end_line_text[ end_column : ] +diff --git a/python/ycm/youcompleteme.py b/python/ycm/youcompleteme.py +index 05da81c8d..8a8cf5ff7 100644 +--- a/python/ycm/youcompleteme.py ++++ b/python/ycm/youcompleteme.py +@@ -15,14 +15,6 @@ + # You should have received a copy of the GNU General Public License + # along with YouCompleteMe. If not, see <http://www.gnu.org/licenses/>. + +-from __future__ import unicode_literals +-from __future__ import print_function +-from __future__ import division +-from __future__ import absolute_import +-# Not installing aliases from python-future; it's unreliable and slow. +-from builtins import * # noqa +- +-from future.utils import iteritems, itervalues + import base64 + import json + import logging +@@ -85,17 +77,12 @@ def PatchNoProxy(): + CORE_MISSING_MESSAGE = ( + 'YCM core library not detected; you need to compile YCM before using it. ' + 'Follow the instructions in the documentation.' ) +-CORE_PYTHON2_MESSAGE = ( +- "YCM core library compiled for Python 2 but loaded in Python 3. " +- "Set the 'g:ycm_server_python_interpreter' option to a Python 2 " +- "interpreter path." ) +-CORE_PYTHON3_MESSAGE = ( +- "YCM core library compiled for Python 3 but loaded in Python 2. " +- "Set the 'g:ycm_server_python_interpreter' option to a Python 3 " +- "interpreter path." ) + CORE_OUTDATED_MESSAGE = ( + 'YCM core library too old; PLEASE RECOMPILE by running the install.py ' + 'script. See the documentation for more details.' ) ++NO_PYTHON2_SUPPORT_MESSAGE = ( ++ 'YCM has dropped support for python2. ' ++ 'You need to recompile it with python3 instead.' ) + SERVER_IDLE_SUICIDE_SECONDS = 1800 # 30 minutes + CLIENT_LOGFILE_FORMAT = 'ycm_' + SERVER_LOGFILE_FORMAT = 'ycmd_{port}_{std}_' +@@ -105,7 +92,7 @@ def PatchNoProxy(): + HANDLE_FLAG_INHERIT = 0x00000001 + + +-class YouCompleteMe( object ): ++class YouCompleteMe: + def __init__( self ): + self._available_completers = {} + self._user_options = None +@@ -261,17 +248,16 @@ def NotifyUserIfServerCrashed( self ): + error_message = CORE_UNEXPECTED_MESSAGE.format( logfile = logfile ) + elif return_code == 4: + error_message = CORE_MISSING_MESSAGE +- elif return_code == 5: +- error_message = CORE_PYTHON2_MESSAGE +- elif return_code == 6: +- error_message = CORE_PYTHON3_MESSAGE + elif return_code == 7: + error_message = CORE_OUTDATED_MESSAGE ++ elif return_code == 8: ++ error_message = NO_PYTHON2_SUPPORT_MESSAGE + else: + error_message = EXIT_CODE_UNEXPECTED_MESSAGE.format( code = return_code, + logfile = logfile ) + +- error_message = SERVER_SHUTDOWN_MESSAGE + ' ' + error_message ++ if return_code != 8: ++ error_message = SERVER_SHUTDOWN_MESSAGE + ' ' + error_message + self._logger.error( error_message ) + vimsupport.PostVimMessage( error_message ) + +@@ -502,7 +488,7 @@ def OnPeriodicTick( self ): + not self._message_poll_requests[ filetype ].Poll( self ) ): + self._message_poll_requests[ filetype ] = None + +- return any( itervalues( self._message_poll_requests ) ) ++ return any( self._message_poll_requests.values() ) + + + def OnFileReadyToParse( self ): +@@ -819,5 +805,5 @@ def _AddUltiSnipsDataIfNeeded( self, extra_data ): + extra_data[ 'ultisnips_snippets' ] = [ + { 'trigger': trigger, + 'description': snippet[ 'description' ] } +- for trigger, snippet in iteritems( snippets ) ++ for trigger, snippet in snippets.items() + ] +diff --git a/test/README.md b/test/README.md +index 0edc0a43a..e109b4fc3 100644 +--- a/test/README.md ++++ b/test/README.md +@@ -8,8 +8,6 @@ your machine. + + * Make sure you have docker installed (duh) + * Run `./docker/manual/run`. +- * This will use a Vim build with python 3 +- * If you want python2, run `./docker/manual/run --py 2` + * You should now be in the container. Your YCM checkout is now mounted in + `$HOME/YouCompleteMe` + * Run the following setup: +@@ -248,15 +246,13 @@ To get a local summary: + + # Docker + +-We generate and push 4 containers: ++We generate and push 2 containers: + + * `youcompleteme/ycm-vim-py3:test` and `youcompleteme/ycm-vim-py3:manual` +-* `youcompleteme/ycm-vim-py2:test` and `youcompleteme/ycm-vim-py2:manual` + + The `:test` tags are the containers that are used by Azure pipelines to run the + tests and contains essentially Ubuntu LTS + the YCM dependencies and a build of +-Vim at a specific version built with either python3 (`-py3`) or python 2 +-(`-py2`) support.. ++Vim at a specific version built with python3 (`-py3`) support. + + The `:manual` tags extend the `:test` tags with a user account that largely + matches the one created by Azure to run our tests. It also installs a basic +diff --git a/test/docker/ci/push b/test/docker/ci/push +index e08178b72..31a8481d9 100755 +--- a/test/docker/ci/push ++++ b/test/docker/ci/push +@@ -2,5 +2,4 @@ + + set -e + +-docker push youcompleteme/ycm-vim-py2:test + docker push youcompleteme/ycm-vim-py3:test +diff --git a/test/docker/ci/rebuild b/test/docker/ci/rebuild +index 1363e3e25..6b384ad04 100755 +--- a/test/docker/ci/rebuild ++++ b/test/docker/ci/rebuild +@@ -8,9 +8,6 @@ else + OPTS="--no-cache" + fi + +-docker build ${OPTS} -t youcompleteme/ycm-vim-py2:test \ +- --build-arg YCM_VIM_PYTHON=python \ +- image/ + docker build ${OPTS} -t youcompleteme/ycm-vim-py3:test \ + --build-arg YCM_VIM_PYTHON=python3 \ + image/ +diff --git a/test/docker/manual/push b/test/docker/manual/push +index bfe60c2d3..ee32addfc 100755 +--- a/test/docker/manual/push ++++ b/test/docker/manual/push +@@ -2,5 +2,4 @@ + + set -e + +-docker push youcompleteme/ycm-vim-py2:manual + docker push youcompleteme/ycm-vim-py3:manual +diff --git a/test/docker/manual/rebuild b/test/docker/manual/rebuild +index c956d657d..9c7f39166 100755 +--- a/test/docker/manual/rebuild ++++ b/test/docker/manual/rebuild +@@ -8,9 +8,6 @@ else + OPTS="--no-cache" + fi + +-docker build ${OPTS} -t youcompleteme/ycm-vim-py2:manual \ +- --build-arg YCM_PYTHON=py2 \ +- image/ + docker build ${OPTS} -t youcompleteme/ycm-vim-py3:manual \ + --build-arg YCM_PYTHON=py3 \ + image/ +diff --git a/third_party/pythonfutures/CHANGES b/third_party/pythonfutures/CHANGES +deleted file mode 100755 +index 81df636f2..000000000 +--- a/third_party/pythonfutures/CHANGES ++++ /dev/null +@@ -1,44 +0,0 @@ +-2.1.4 +-===== +- +-- Ported the library again from Python 3.2.5 to get the latest bug fixes +- +- +-2.1.3 +-===== +- +-- Fixed race condition in wait(return_when=ALL_COMPLETED) +- (http://bugs.python.org/issue14406) -- thanks Ralf Schmitt +-- Added missing setUp() methods to several test classes +- +- +-2.1.2 +-===== +- +-- Fixed installation problem on Python 3.1 +- +- +-2.1.1 +-===== +- +-- Fixed missing 'concurrent' package declaration in setup.py +- +- +-2.1 +-=== +- +-- Moved the code from the 'futures' package to 'concurrent.futures' to provide +- a drop in backport that matches the code in Python 3.2 standard library +-- Deprecated the old 'futures' package +- +- +-2.0 +-=== +- +-- Changed implementation to match PEP 3148 +- +- +-1.0 +-=== +- +-Initial release. +diff --git a/third_party/pythonfutures/LICENSE b/third_party/pythonfutures/LICENSE +deleted file mode 100755 +index c430db0f1..000000000 +--- a/third_party/pythonfutures/LICENSE ++++ /dev/null +@@ -1,21 +0,0 @@ +-Copyright 2009 Brian Quinlan. All rights reserved. +- +-Redistribution and use in source and binary forms, with or without modification, +-are permitted provided that the following conditions are met: +- +- 1. Redistributions of source code must retain the above copyright notice, +- this list of conditions and the following disclaimer. +- 2. Redistributions in binary form must reproduce the above copyright notice, +- this list of conditions and the following disclaimer in the documentation +- and/or other materials provided with the distribution. +- +-THIS SOFTWARE IS PROVIDED BY BRIAN QUINLAN "AS IS" AND ANY EXPRESS OR IMPLIED +-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +-HALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +-ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\ No newline at end of file +diff --git a/third_party/pythonfutures/concurrent/__init__.py b/third_party/pythonfutures/concurrent/__init__.py +deleted file mode 100755 +index b36383a61..000000000 +--- a/third_party/pythonfutures/concurrent/__init__.py ++++ /dev/null +@@ -1,3 +0,0 @@ +-from pkgutil import extend_path +- +-__path__ = extend_path(__path__, __name__) +diff --git a/third_party/pythonfutures/concurrent/futures/__init__.py b/third_party/pythonfutures/concurrent/futures/__init__.py +deleted file mode 100755 +index b5231f8aa..000000000 +--- a/third_party/pythonfutures/concurrent/futures/__init__.py ++++ /dev/null +@@ -1,18 +0,0 @@ +-# Copyright 2009 Brian Quinlan. All Rights Reserved. +-# Licensed to PSF under a Contributor Agreement. +- +-"""Execute computations asynchronously using threads or processes.""" +- +-__author__ = 'Brian Quinlan (brian@sweetapp.com)' +- +-from concurrent.futures._base import (FIRST_COMPLETED, +- FIRST_EXCEPTION, +- ALL_COMPLETED, +- CancelledError, +- TimeoutError, +- Future, +- Executor, +- wait, +- as_completed) +-from concurrent.futures.process import ProcessPoolExecutor +-from concurrent.futures.thread import ThreadPoolExecutor +diff --git a/third_party/pythonfutures/concurrent/futures/_base.py b/third_party/pythonfutures/concurrent/futures/_base.py +deleted file mode 100755 +index 8ed69b7d9..000000000 +--- a/third_party/pythonfutures/concurrent/futures/_base.py ++++ /dev/null +@@ -1,574 +0,0 @@ +-# Copyright 2009 Brian Quinlan. All Rights Reserved. +-# Licensed to PSF under a Contributor Agreement. +- +-from __future__ import with_statement +-import logging +-import threading +-import time +- +-try: +- from collections import namedtuple +-except ImportError: +- from concurrent.futures._compat import namedtuple +- +-__author__ = 'Brian Quinlan (brian@sweetapp.com)' +- +-FIRST_COMPLETED = 'FIRST_COMPLETED' +-FIRST_EXCEPTION = 'FIRST_EXCEPTION' +-ALL_COMPLETED = 'ALL_COMPLETED' +-_AS_COMPLETED = '_AS_COMPLETED' +- +-# Possible future states (for internal use by the futures package). +-PENDING = 'PENDING' +-RUNNING = 'RUNNING' +-# The future was cancelled by the user... +-CANCELLED = 'CANCELLED' +-# ...and _Waiter.add_cancelled() was called by a worker. +-CANCELLED_AND_NOTIFIED = 'CANCELLED_AND_NOTIFIED' +-FINISHED = 'FINISHED' +- +-_FUTURE_STATES = [ +- PENDING, +- RUNNING, +- CANCELLED, +- CANCELLED_AND_NOTIFIED, +- FINISHED +-] +- +-_STATE_TO_DESCRIPTION_MAP = { +- PENDING: "pending", +- RUNNING: "running", +- CANCELLED: "cancelled", +- CANCELLED_AND_NOTIFIED: "cancelled", +- FINISHED: "finished" +-} +- +-# Logger for internal use by the futures package. +-LOGGER = logging.getLogger("concurrent.futures") +- +-class Error(Exception): +- """Base class for all future-related exceptions.""" +- pass +- +-class CancelledError(Error): +- """The Future was cancelled.""" +- pass +- +-class TimeoutError(Error): +- """The operation exceeded the given deadline.""" +- pass +- +-class _Waiter(object): +- """Provides the event that wait() and as_completed() block on.""" +- def __init__(self): +- self.event = threading.Event() +- self.finished_futures = [] +- +- def add_result(self, future): +- self.finished_futures.append(future) +- +- def add_exception(self, future): +- self.finished_futures.append(future) +- +- def add_cancelled(self, future): +- self.finished_futures.append(future) +- +-class _AsCompletedWaiter(_Waiter): +- """Used by as_completed().""" +- +- def __init__(self): +- super(_AsCompletedWaiter, self).__init__() +- self.lock = threading.Lock() +- +- def add_result(self, future): +- with self.lock: +- super(_AsCompletedWaiter, self).add_result(future) +- self.event.set() +- +- def add_exception(self, future): +- with self.lock: +- super(_AsCompletedWaiter, self).add_exception(future) +- self.event.set() +- +- def add_cancelled(self, future): +- with self.lock: +- super(_AsCompletedWaiter, self).add_cancelled(future) +- self.event.set() +- +-class _FirstCompletedWaiter(_Waiter): +- """Used by wait(return_when=FIRST_COMPLETED).""" +- +- def add_result(self, future): +- super(_FirstCompletedWaiter, self).add_result(future) +- self.event.set() +- +- def add_exception(self, future): +- super(_FirstCompletedWaiter, self).add_exception(future) +- self.event.set() +- +- def add_cancelled(self, future): +- super(_FirstCompletedWaiter, self).add_cancelled(future) +- self.event.set() +- +-class _AllCompletedWaiter(_Waiter): +- """Used by wait(return_when=FIRST_EXCEPTION and ALL_COMPLETED).""" +- +- def __init__(self, num_pending_calls, stop_on_exception): +- self.num_pending_calls = num_pending_calls +- self.stop_on_exception = stop_on_exception +- self.lock = threading.Lock() +- super(_AllCompletedWaiter, self).__init__() +- +- def _decrement_pending_calls(self): +- with self.lock: +- self.num_pending_calls -= 1 +- if not self.num_pending_calls: +- self.event.set() +- +- def add_result(self, future): +- super(_AllCompletedWaiter, self).add_result(future) +- self._decrement_pending_calls() +- +- def add_exception(self, future): +- super(_AllCompletedWaiter, self).add_exception(future) +- if self.stop_on_exception: +- self.event.set() +- else: +- self._decrement_pending_calls() +- +- def add_cancelled(self, future): +- super(_AllCompletedWaiter, self).add_cancelled(future) +- self._decrement_pending_calls() +- +-class _AcquireFutures(object): +- """A context manager that does an ordered acquire of Future conditions.""" +- +- def __init__(self, futures): +- self.futures = sorted(futures, key=id) +- +- def __enter__(self): +- for future in self.futures: +- future._condition.acquire() +- +- def __exit__(self, *args): +- for future in self.futures: +- future._condition.release() +- +-def _create_and_install_waiters(fs, return_when): +- if return_when == _AS_COMPLETED: +- waiter = _AsCompletedWaiter() +- elif return_when == FIRST_COMPLETED: +- waiter = _FirstCompletedWaiter() +- else: +- pending_count = sum( +- f._state not in [CANCELLED_AND_NOTIFIED, FINISHED] for f in fs) +- +- if return_when == FIRST_EXCEPTION: +- waiter = _AllCompletedWaiter(pending_count, stop_on_exception=True) +- elif return_when == ALL_COMPLETED: +- waiter = _AllCompletedWaiter(pending_count, stop_on_exception=False) +- else: +- raise ValueError("Invalid return condition: %r" % return_when) +- +- for f in fs: +- f._waiters.append(waiter) +- +- return waiter +- +-def as_completed(fs, timeout=None): +- """An iterator over the given futures that yields each as it completes. +- +- Args: +- fs: The sequence of Futures (possibly created by different Executors) to +- iterate over. +- timeout: The maximum number of seconds to wait. If None, then there +- is no limit on the wait time. +- +- Returns: +- An iterator that yields the given Futures as they complete (finished or +- cancelled). +- +- Raises: +- TimeoutError: If the entire result iterator could not be generated +- before the given timeout. +- """ +- if timeout is not None: +- end_time = timeout + time.time() +- +- with _AcquireFutures(fs): +- finished = set( +- f for f in fs +- if f._state in [CANCELLED_AND_NOTIFIED, FINISHED]) +- pending = set(fs) - finished +- waiter = _create_and_install_waiters(fs, _AS_COMPLETED) +- +- try: +- for future in finished: +- yield future +- +- while pending: +- if timeout is None: +- wait_timeout = None +- else: +- wait_timeout = end_time - time.time() +- if wait_timeout < 0: +- raise TimeoutError( +- '%d (of %d) futures unfinished' % ( +- len(pending), len(fs))) +- +- waiter.event.wait(wait_timeout) +- +- with waiter.lock: +- finished = waiter.finished_futures +- waiter.finished_futures = [] +- waiter.event.clear() +- +- for future in finished: +- yield future +- pending.remove(future) +- +- finally: +- for f in fs: +- f._waiters.remove(waiter) +- +-DoneAndNotDoneFutures = namedtuple( +- 'DoneAndNotDoneFutures', 'done not_done') +-def wait(fs, timeout=None, return_when=ALL_COMPLETED): +- """Wait for the futures in the given sequence to complete. +- +- Args: +- fs: The sequence of Futures (possibly created by different Executors) to +- wait upon. +- timeout: The maximum number of seconds to wait. If None, then there +- is no limit on the wait time. +- return_when: Indicates when this function should return. The options +- are: +- +- FIRST_COMPLETED - Return when any future finishes or is +- cancelled. +- FIRST_EXCEPTION - Return when any future finishes by raising an +- exception. If no future raises an exception +- then it is equivalent to ALL_COMPLETED. +- ALL_COMPLETED - Return when all futures finish or are cancelled. +- +- Returns: +- A named 2-tuple of sets. The first set, named 'done', contains the +- futures that completed (is finished or cancelled) before the wait +- completed. The second set, named 'not_done', contains uncompleted +- futures. +- """ +- with _AcquireFutures(fs): +- done = set(f for f in fs +- if f._state in [CANCELLED_AND_NOTIFIED, FINISHED]) +- not_done = set(fs) - done +- +- if (return_when == FIRST_COMPLETED) and done: +- return DoneAndNotDoneFutures(done, not_done) +- elif (return_when == FIRST_EXCEPTION) and done: +- if any(f for f in done +- if not f.cancelled() and f.exception() is not None): +- return DoneAndNotDoneFutures(done, not_done) +- +- if len(done) == len(fs): +- return DoneAndNotDoneFutures(done, not_done) +- +- waiter = _create_and_install_waiters(fs, return_when) +- +- waiter.event.wait(timeout) +- for f in fs: +- f._waiters.remove(waiter) +- +- done.update(waiter.finished_futures) +- return DoneAndNotDoneFutures(done, set(fs) - done) +- +-class Future(object): +- """Represents the result of an asynchronous computation.""" +- +- def __init__(self): +- """Initializes the future. Should not be called by clients.""" +- self._condition = threading.Condition() +- self._state = PENDING +- self._result = None +- self._exception = None +- self._waiters = [] +- self._done_callbacks = [] +- +- def _invoke_callbacks(self): +- for callback in self._done_callbacks: +- try: +- callback(self) +- except Exception: +- LOGGER.exception('exception calling callback for %r', self) +- +- def __repr__(self): +- with self._condition: +- if self._state == FINISHED: +- if self._exception: +- return '<Future at %s state=%s raised %s>' % ( +- hex(id(self)), +- _STATE_TO_DESCRIPTION_MAP[self._state], +- self._exception.__class__.__name__) +- else: +- return '<Future at %s state=%s returned %s>' % ( +- hex(id(self)), +- _STATE_TO_DESCRIPTION_MAP[self._state], +- self._result.__class__.__name__) +- return '<Future at %s state=%s>' % ( +- hex(id(self)), +- _STATE_TO_DESCRIPTION_MAP[self._state]) +- +- def cancel(self): +- """Cancel the future if possible. +- +- Returns True if the future was cancelled, False otherwise. A future +- cannot be cancelled if it is running or has already completed. +- """ +- with self._condition: +- if self._state in [RUNNING, FINISHED]: +- return False +- +- if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]: +- return True +- +- self._state = CANCELLED +- self._condition.notify_all() +- +- self._invoke_callbacks() +- return True +- +- def cancelled(self): +- """Return True if the future has cancelled.""" +- with self._condition: +- return self._state in [CANCELLED, CANCELLED_AND_NOTIFIED] +- +- def running(self): +- """Return True if the future is currently executing.""" +- with self._condition: +- return self._state == RUNNING +- +- def done(self): +- """Return True of the future was cancelled or finished executing.""" +- with self._condition: +- return self._state in [CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED] +- +- def __get_result(self): +- if self._exception: +- raise self._exception +- else: +- return self._result +- +- def add_done_callback(self, fn): +- """Attaches a callable that will be called when the future finishes. +- +- Args: +- fn: A callable that will be called with this future as its only +- argument when the future completes or is cancelled. The callable +- will always be called by a thread in the same process in which +- it was added. If the future has already completed or been +- cancelled then the callable will be called immediately. These +- callables are called in the order that they were added. +- """ +- with self._condition: +- if self._state not in [CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED]: +- self._done_callbacks.append(fn) +- return +- fn(self) +- +- def result(self, timeout=None): +- """Return the result of the call that the future represents. +- +- Args: +- timeout: The number of seconds to wait for the result if the future +- isn't done. If None, then there is no limit on the wait time. +- +- Returns: +- The result of the call that the future represents. +- +- Raises: +- CancelledError: If the future was cancelled. +- TimeoutError: If the future didn't finish executing before the given +- timeout. +- Exception: If the call raised then that exception will be raised. +- """ +- with self._condition: +- if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]: +- raise CancelledError() +- elif self._state == FINISHED: +- return self.__get_result() +- +- self._condition.wait(timeout) +- +- if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]: +- raise CancelledError() +- elif self._state == FINISHED: +- return self.__get_result() +- else: +- raise TimeoutError() +- +- def exception(self, timeout=None): +- """Return the exception raised by the call that the future represents. +- +- Args: +- timeout: The number of seconds to wait for the exception if the +- future isn't done. If None, then there is no limit on the wait +- time. +- +- Returns: +- The exception raised by the call that the future represents or None +- if the call completed without raising. +- +- Raises: +- CancelledError: If the future was cancelled. +- TimeoutError: If the future didn't finish executing before the given +- timeout. +- """ +- +- with self._condition: +- if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]: +- raise CancelledError() +- elif self._state == FINISHED: +- return self._exception +- +- self._condition.wait(timeout) +- +- if self._state in [CANCELLED, CANCELLED_AND_NOTIFIED]: +- raise CancelledError() +- elif self._state == FINISHED: +- return self._exception +- else: +- raise TimeoutError() +- +- # The following methods should only be used by Executors and in tests. +- def set_running_or_notify_cancel(self): +- """Mark the future as running or process any cancel notifications. +- +- Should only be used by Executor implementations and unit tests. +- +- If the future has been cancelled (cancel() was called and returned +- True) then any threads waiting on the future completing (though calls +- to as_completed() or wait()) are notified and False is returned. +- +- If the future was not cancelled then it is put in the running state +- (future calls to running() will return True) and True is returned. +- +- This method should be called by Executor implementations before +- executing the work associated with this future. If this method returns +- False then the work should not be executed. +- +- Returns: +- False if the Future was cancelled, True otherwise. +- +- Raises: +- RuntimeError: if this method was already called or if set_result() +- or set_exception() was called. +- """ +- with self._condition: +- if self._state == CANCELLED: +- self._state = CANCELLED_AND_NOTIFIED +- for waiter in self._waiters: +- waiter.add_cancelled(self) +- # self._condition.notify_all() is not necessary because +- # self.cancel() triggers a notification. +- return False +- elif self._state == PENDING: +- self._state = RUNNING +- return True +- else: +- LOGGER.critical('Future %s in unexpected state: %s', +- id(self.future), +- self.future._state) +- raise RuntimeError('Future in unexpected state') +- +- def set_result(self, result): +- """Sets the return value of work associated with the future. +- +- Should only be used by Executor implementations and unit tests. +- """ +- with self._condition: +- self._result = result +- self._state = FINISHED +- for waiter in self._waiters: +- waiter.add_result(self) +- self._condition.notify_all() +- self._invoke_callbacks() +- +- def set_exception(self, exception): +- """Sets the result of the future as being the given exception. +- +- Should only be used by Executor implementations and unit tests. +- """ +- with self._condition: +- self._exception = exception +- self._state = FINISHED +- for waiter in self._waiters: +- waiter.add_exception(self) +- self._condition.notify_all() +- self._invoke_callbacks() +- +-class Executor(object): +- """This is an abstract base class for concrete asynchronous executors.""" +- +- def submit(self, fn, *args, **kwargs): +- """Submits a callable to be executed with the given arguments. +- +- Schedules the callable to be executed as fn(*args, **kwargs) and returns +- a Future instance representing the execution of the callable. +- +- Returns: +- A Future representing the given call. +- """ +- raise NotImplementedError() +- +- def map(self, fn, *iterables, **kwargs): +- """Returns a iterator equivalent to map(fn, iter). +- +- Args: +- fn: A callable that will take as many arguments as there are +- passed iterables. +- timeout: The maximum number of seconds to wait. If None, then there +- is no limit on the wait time. +- +- Returns: +- An iterator equivalent to: map(func, *iterables) but the calls may +- be evaluated out-of-order. +- +- Raises: +- TimeoutError: If the entire result iterator could not be generated +- before the given timeout. +- Exception: If fn(*args) raises for any values. +- """ +- timeout = kwargs.get('timeout') +- if timeout is not None: +- end_time = timeout + time.time() +- +- fs = [self.submit(fn, *args) for args in zip(*iterables)] +- +- try: +- for future in fs: +- if timeout is None: +- yield future.result() +- else: +- yield future.result(end_time - time.time()) +- finally: +- for future in fs: +- future.cancel() +- +- def shutdown(self, wait=True): +- """Clean-up the resources associated with the Executor. +- +- It is safe to call this method several times. Otherwise, no other +- methods can be called after this one. +- +- Args: +- wait: If True then shutdown will not return until all running +- futures have finished executing and the resources used by the +- executor have been reclaimed. +- """ +- pass +- +- def __enter__(self): +- return self +- +- def __exit__(self, exc_type, exc_val, exc_tb): +- self.shutdown(wait=True) +- return False +diff --git a/third_party/pythonfutures/concurrent/futures/_compat.py b/third_party/pythonfutures/concurrent/futures/_compat.py +deleted file mode 100755 +index 11462326b..000000000 +--- a/third_party/pythonfutures/concurrent/futures/_compat.py ++++ /dev/null +@@ -1,101 +0,0 @@ +-from keyword import iskeyword as _iskeyword +-from operator import itemgetter as _itemgetter +-import sys as _sys +- +- +-def namedtuple(typename, field_names): +- """Returns a new subclass of tuple with named fields. +- +- >>> Point = namedtuple('Point', 'x y') +- >>> Point.__doc__ # docstring for the new class +- 'Point(x, y)' +- >>> p = Point(11, y=22) # instantiate with positional args or keywords +- >>> p[0] + p[1] # indexable like a plain tuple +- 33 +- >>> x, y = p # unpack like a regular tuple +- >>> x, y +- (11, 22) +- >>> p.x + p.y # fields also accessable by name +- 33 +- >>> d = p._asdict() # convert to a dictionary +- >>> d['x'] +- 11 +- >>> Point(**d) # convert from a dictionary +- Point(x=11, y=22) +- >>> p._replace(x=100) # _replace() is like str.replace() but targets named fields +- Point(x=100, y=22) +- +- """ +- +- # Parse and validate the field names. Validation serves two purposes, +- # generating informative error messages and preventing template injection attacks. +- if isinstance(field_names, basestring): +- field_names = field_names.replace(',', ' ').split() # names separated by whitespace and/or commas +- field_names = tuple(map(str, field_names)) +- for name in (typename,) + field_names: +- if not all(c.isalnum() or c=='_' for c in name): +- raise ValueError('Type names and field names can only contain alphanumeric characters and underscores: %r' % name) +- if _iskeyword(name): +- raise ValueError('Type names and field names cannot be a keyword: %r' % name) +- if name[0].isdigit(): +- raise ValueError('Type names and field names cannot start with a number: %r' % name) +- seen_names = set() +- for name in field_names: +- if name.startswith('_'): +- raise ValueError('Field names cannot start with an underscore: %r' % name) +- if name in seen_names: +- raise ValueError('Encountered duplicate field name: %r' % name) +- seen_names.add(name) +- +- # Create and fill-in the class template +- numfields = len(field_names) +- argtxt = repr(field_names).replace("'", "")[1:-1] # tuple repr without parens or quotes +- reprtxt = ', '.join('%s=%%r' % name for name in field_names) +- dicttxt = ', '.join('%r: t[%d]' % (name, pos) for pos, name in enumerate(field_names)) +- template = '''class %(typename)s(tuple): +- '%(typename)s(%(argtxt)s)' \n +- __slots__ = () \n +- _fields = %(field_names)r \n +- def __new__(_cls, %(argtxt)s): +- return _tuple.__new__(_cls, (%(argtxt)s)) \n +- @classmethod +- def _make(cls, iterable, new=tuple.__new__, len=len): +- 'Make a new %(typename)s object from a sequence or iterable' +- result = new(cls, iterable) +- if len(result) != %(numfields)d: +- raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result)) +- return result \n +- def __repr__(self): +- return '%(typename)s(%(reprtxt)s)' %% self \n +- def _asdict(t): +- 'Return a new dict which maps field names to their values' +- return {%(dicttxt)s} \n +- def _replace(_self, **kwds): +- 'Return a new %(typename)s object replacing specified fields with new values' +- result = _self._make(map(kwds.pop, %(field_names)r, _self)) +- if kwds: +- raise ValueError('Got unexpected field names: %%r' %% kwds.keys()) +- return result \n +- def __getnewargs__(self): +- return tuple(self) \n\n''' % locals() +- for i, name in enumerate(field_names): +- template += ' %s = _property(_itemgetter(%d))\n' % (name, i) +- +- # Execute the template string in a temporary namespace and +- # support tracing utilities by setting a value for frame.f_globals['__name__'] +- namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename, +- _property=property, _tuple=tuple) +- try: +- exec(template, namespace) +- except SyntaxError: +- e = _sys.exc_info()[1] +- raise SyntaxError(e.message + ':\n' + template) +- result = namespace[typename] +- +- # For pickling to work, the __module__ variable needs to be set to the frame +- # where the named tuple is created. Bypass this step in enviroments where +- # sys._getframe is not defined (Jython for example). +- if hasattr(_sys, '_getframe'): +- result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__') +- +- return result +diff --git a/third_party/pythonfutures/concurrent/futures/process.py b/third_party/pythonfutures/concurrent/futures/process.py +deleted file mode 100755 +index 98684f8e8..000000000 +--- a/third_party/pythonfutures/concurrent/futures/process.py ++++ /dev/null +@@ -1,363 +0,0 @@ +-# Copyright 2009 Brian Quinlan. All Rights Reserved. +-# Licensed to PSF under a Contributor Agreement. +- +-"""Implements ProcessPoolExecutor. +- +-The follow diagram and text describe the data-flow through the system: +- +-|======================= In-process =====================|== Out-of-process ==| +- +-+----------+ +----------+ +--------+ +-----------+ +---------+ +-| | => | Work Ids | => | | => | Call Q | => | | +-| | +----------+ | | +-----------+ | | +-| | | ... | | | | ... | | | +-| | | 6 | | | | 5, call() | | | +-| | | 7 | | | | ... | | | +-| Process | | ... | | Local | +-----------+ | Process | +-| Pool | +----------+ | Worker | | #1..n | +-| Executor | | Thread | | | +-| | +----------- + | | +-----------+ | | +-| | <=> | Work Items | <=> | | <= | Result Q | <= | | +-| | +------------+ | | +-----------+ | | +-| | | 6: call() | | | | ... | | | +-| | | future | | | | 4, result | | | +-| | | ... | | | | 3, except | | | +-+----------+ +------------+ +--------+ +-----------+ +---------+ +- +-Executor.submit() called: +-- creates a uniquely numbered _WorkItem and adds it to the "Work Items" dict +-- adds the id of the _WorkItem to the "Work Ids" queue +- +-Local worker thread: +-- reads work ids from the "Work Ids" queue and looks up the corresponding +- WorkItem from the "Work Items" dict: if the work item has been cancelled then +- it is simply removed from the dict, otherwise it is repackaged as a +- _CallItem and put in the "Call Q". New _CallItems are put in the "Call Q" +- until "Call Q" is full. NOTE: the size of the "Call Q" is kept small because +- calls placed in the "Call Q" can no longer be cancelled with Future.cancel(). +-- reads _ResultItems from "Result Q", updates the future stored in the +- "Work Items" dict and deletes the dict entry +- +-Process #1..n: +-- reads _CallItems from "Call Q", executes the calls, and puts the resulting +- _ResultItems in "Request Q" +-""" +- +-from __future__ import with_statement +-import atexit +-import multiprocessing +-import threading +-import weakref +-import sys +- +-from concurrent.futures import _base +- +-try: +- import queue +-except ImportError: +- import Queue as queue +- +-__author__ = 'Brian Quinlan (brian@sweetapp.com)' +- +-# Workers are created as daemon threads and processes. This is done to allow the +-# interpreter to exit when there are still idle processes in a +-# ProcessPoolExecutor's process pool (i.e. shutdown() was not called). However, +-# allowing workers to die with the interpreter has two undesirable properties: +-# - The workers would still be running during interpretor shutdown, +-# meaning that they would fail in unpredictable ways. +-# - The workers could be killed while evaluating a work item, which could +-# be bad if the callable being evaluated has external side-effects e.g. +-# writing to a file. +-# +-# To work around this problem, an exit handler is installed which tells the +-# workers to exit when their work queues are empty and then waits until the +-# threads/processes finish. +- +-_threads_queues = weakref.WeakKeyDictionary() +-_shutdown = False +- +-def _python_exit(): +- global _shutdown +- _shutdown = True +- items = list(_threads_queues.items()) +- for t, q in items: +- q.put(None) +- for t, q in items: +- t.join() +- +-# Controls how many more calls than processes will be queued in the call queue. +-# A smaller number will mean that processes spend more time idle waiting for +-# work while a larger number will make Future.cancel() succeed less frequently +-# (Futures in the call queue cannot be cancelled). +-EXTRA_QUEUED_CALLS = 1 +- +-class _WorkItem(object): +- def __init__(self, future, fn, args, kwargs): +- self.future = future +- self.fn = fn +- self.args = args +- self.kwargs = kwargs +- +-class _ResultItem(object): +- def __init__(self, work_id, exception=None, result=None): +- self.work_id = work_id +- self.exception = exception +- self.result = result +- +-class _CallItem(object): +- def __init__(self, work_id, fn, args, kwargs): +- self.work_id = work_id +- self.fn = fn +- self.args = args +- self.kwargs = kwargs +- +-def _process_worker(call_queue, result_queue): +- """Evaluates calls from call_queue and places the results in result_queue. +- +- This worker is run in a separate process. +- +- Args: +- call_queue: A multiprocessing.Queue of _CallItems that will be read and +- evaluated by the worker. +- result_queue: A multiprocessing.Queue of _ResultItems that will written +- to by the worker. +- shutdown: A multiprocessing.Event that will be set as a signal to the +- worker that it should exit when call_queue is empty. +- """ +- while True: +- call_item = call_queue.get(block=True) +- if call_item is None: +- # Wake up queue management thread +- result_queue.put(None) +- return +- try: +- r = call_item.fn(*call_item.args, **call_item.kwargs) +- except BaseException: +- e = sys.exc_info()[1] +- result_queue.put(_ResultItem(call_item.work_id, +- exception=e)) +- else: +- result_queue.put(_ResultItem(call_item.work_id, +- result=r)) +- +-def _add_call_item_to_queue(pending_work_items, +- work_ids, +- call_queue): +- """Fills call_queue with _WorkItems from pending_work_items. +- +- This function never blocks. +- +- Args: +- pending_work_items: A dict mapping work ids to _WorkItems e.g. +- {5: <_WorkItem...>, 6: <_WorkItem...>, ...} +- work_ids: A queue.Queue of work ids e.g. Queue([5, 6, ...]). Work ids +- are consumed and the corresponding _WorkItems from +- pending_work_items are transformed into _CallItems and put in +- call_queue. +- call_queue: A multiprocessing.Queue that will be filled with _CallItems +- derived from _WorkItems. +- """ +- while True: +- if call_queue.full(): +- return +- try: +- work_id = work_ids.get(block=False) +- except queue.Empty: +- return +- else: +- work_item = pending_work_items[work_id] +- +- if work_item.future.set_running_or_notify_cancel(): +- call_queue.put(_CallItem(work_id, +- work_item.fn, +- work_item.args, +- work_item.kwargs), +- block=True) +- else: +- del pending_work_items[work_id] +- continue +- +-def _queue_management_worker(executor_reference, +- processes, +- pending_work_items, +- work_ids_queue, +- call_queue, +- result_queue): +- """Manages the communication between this process and the worker processes. +- +- This function is run in a local thread. +- +- Args: +- executor_reference: A weakref.ref to the ProcessPoolExecutor that owns +- this thread. Used to determine if the ProcessPoolExecutor has been +- garbage collected and that this function can exit. +- process: A list of the multiprocessing.Process instances used as +- workers. +- pending_work_items: A dict mapping work ids to _WorkItems e.g. +- {5: <_WorkItem...>, 6: <_WorkItem...>, ...} +- work_ids_queue: A queue.Queue of work ids e.g. Queue([5, 6, ...]). +- call_queue: A multiprocessing.Queue that will be filled with _CallItems +- derived from _WorkItems for processing by the process workers. +- result_queue: A multiprocessing.Queue of _ResultItems generated by the +- process workers. +- """ +- nb_shutdown_processes = [0] +- def shutdown_one_process(): +- """Tell a worker to terminate, which will in turn wake us again""" +- call_queue.put(None) +- nb_shutdown_processes[0] += 1 +- while True: +- _add_call_item_to_queue(pending_work_items, +- work_ids_queue, +- call_queue) +- +- result_item = result_queue.get(block=True) +- if result_item is not None: +- work_item = pending_work_items[result_item.work_id] +- del pending_work_items[result_item.work_id] +- +- if result_item.exception: +- work_item.future.set_exception(result_item.exception) +- else: +- work_item.future.set_result(result_item.result) +- # Check whether we should start shutting down. +- executor = executor_reference() +- # No more work items can be added if: +- # - The interpreter is shutting down OR +- # - The executor that owns this worker has been collected OR +- # - The executor that owns this worker has been shutdown. +- if _shutdown or executor is None or executor._shutdown_thread: +- # Since no new work items can be added, it is safe to shutdown +- # this thread if there are no pending work items. +- if not pending_work_items: +- while nb_shutdown_processes[0] < len(processes): +- shutdown_one_process() +- # If .join() is not called on the created processes then +- # some multiprocessing.Queue methods may deadlock on Mac OS +- # X. +- for p in processes: +- p.join() +- call_queue.close() +- return +- del executor +- +-_system_limits_checked = False +-_system_limited = None +-def _check_system_limits(): +- global _system_limits_checked, _system_limited +- if _system_limits_checked: +- if _system_limited: +- raise NotImplementedError(_system_limited) +- _system_limits_checked = True +- try: +- import os +- nsems_max = os.sysconf("SC_SEM_NSEMS_MAX") +- except (AttributeError, ValueError): +- # sysconf not available or setting not available +- return +- if nsems_max == -1: +- # indetermine limit, assume that limit is determined +- # by available memory only +- return +- if nsems_max >= 256: +- # minimum number of semaphores available +- # according to POSIX +- return +- _system_limited = "system provides too few semaphores (%d available, 256 necessary)" % nsems_max +- raise NotImplementedError(_system_limited) +- +-class ProcessPoolExecutor(_base.Executor): +- def __init__(self, max_workers=None): +- """Initializes a new ProcessPoolExecutor instance. +- +- Args: +- max_workers: The maximum number of processes that can be used to +- execute the given calls. If None or not given then as many +- worker processes will be created as the machine has processors. +- """ +- _check_system_limits() +- +- if max_workers is None: +- self._max_workers = multiprocessing.cpu_count() +- else: +- self._max_workers = max_workers +- +- # Make the call queue slightly larger than the number of processes to +- # prevent the worker processes from idling. But don't make it too big +- # because futures in the call queue cannot be cancelled. +- self._call_queue = multiprocessing.Queue(self._max_workers + +- EXTRA_QUEUED_CALLS) +- self._result_queue = multiprocessing.Queue() +- self._work_ids = queue.Queue() +- self._queue_management_thread = None +- self._processes = set() +- +- # Shutdown is a two-step process. +- self._shutdown_thread = False +- self._shutdown_lock = threading.Lock() +- self._queue_count = 0 +- self._pending_work_items = {} +- +- def _start_queue_management_thread(self): +- # When the executor gets lost, the weakref callback will wake up +- # the queue management thread. +- def weakref_cb(_, q=self._result_queue): +- q.put(None) +- if self._queue_management_thread is None: +- self._queue_management_thread = threading.Thread( +- target=_queue_management_worker, +- args=(weakref.ref(self, weakref_cb), +- self._processes, +- self._pending_work_items, +- self._work_ids, +- self._call_queue, +- self._result_queue)) +- self._queue_management_thread.daemon = True +- self._queue_management_thread.start() +- _threads_queues[self._queue_management_thread] = self._result_queue +- +- def _adjust_process_count(self): +- for _ in range(len(self._processes), self._max_workers): +- p = multiprocessing.Process( +- target=_process_worker, +- args=(self._call_queue, +- self._result_queue)) +- p.start() +- self._processes.add(p) +- +- def submit(self, fn, *args, **kwargs): +- with self._shutdown_lock: +- if self._shutdown_thread: +- raise RuntimeError('cannot schedule new futures after shutdown') +- +- f = _base.Future() +- w = _WorkItem(f, fn, args, kwargs) +- +- self._pending_work_items[self._queue_count] = w +- self._work_ids.put(self._queue_count) +- self._queue_count += 1 +- # Wake up queue management thread +- self._result_queue.put(None) +- +- self._start_queue_management_thread() +- self._adjust_process_count() +- return f +- submit.__doc__ = _base.Executor.submit.__doc__ +- +- def shutdown(self, wait=True): +- with self._shutdown_lock: +- self._shutdown_thread = True +- if self._queue_management_thread: +- # Wake up queue management thread +- self._result_queue.put(None) +- if wait: +- self._queue_management_thread.join() +- # To reduce the risk of openning too many files, remove references to +- # objects that use file descriptors. +- self._queue_management_thread = None +- self._call_queue = None +- self._result_queue = None +- self._processes = None +- shutdown.__doc__ = _base.Executor.shutdown.__doc__ +- +-atexit.register(_python_exit) +diff --git a/third_party/pythonfutures/concurrent/futures/thread.py b/third_party/pythonfutures/concurrent/futures/thread.py +deleted file mode 100755 +index a45959d3b..000000000 +--- a/third_party/pythonfutures/concurrent/futures/thread.py ++++ /dev/null +@@ -1,138 +0,0 @@ +-# Copyright 2009 Brian Quinlan. All Rights Reserved. +-# Licensed to PSF under a Contributor Agreement. +- +-"""Implements ThreadPoolExecutor.""" +- +-from __future__ import with_statement +-import atexit +-import threading +-import weakref +-import sys +- +-from concurrent.futures import _base +- +-try: +- import queue +-except ImportError: +- import Queue as queue +- +-__author__ = 'Brian Quinlan (brian@sweetapp.com)' +- +-# Workers are created as daemon threads. This is done to allow the interpreter +-# to exit when there are still idle threads in a ThreadPoolExecutor's thread +-# pool (i.e. shutdown() was not called). However, allowing workers to die with +-# the interpreter has two undesirable properties: +-# - The workers would still be running during interpretor shutdown, +-# meaning that they would fail in unpredictable ways. +-# - The workers could be killed while evaluating a work item, which could +-# be bad if the callable being evaluated has external side-effects e.g. +-# writing to a file. +-# +-# To work around this problem, an exit handler is installed which tells the +-# workers to exit when their work queues are empty and then waits until the +-# threads finish. +- +-_threads_queues = weakref.WeakKeyDictionary() +-_shutdown = False +- +-def _python_exit(): +- global _shutdown +- _shutdown = True +- items = list(_threads_queues.items()) +- for t, q in items: +- q.put(None) +- for t, q in items: +- t.join() +- +-atexit.register(_python_exit) +- +-class _WorkItem(object): +- def __init__(self, future, fn, args, kwargs): +- self.future = future +- self.fn = fn +- self.args = args +- self.kwargs = kwargs +- +- def run(self): +- if not self.future.set_running_or_notify_cancel(): +- return +- +- try: +- result = self.fn(*self.args, **self.kwargs) +- except BaseException: +- e = sys.exc_info()[1] +- self.future.set_exception(e) +- else: +- self.future.set_result(result) +- +-def _worker(executor_reference, work_queue): +- try: +- while True: +- work_item = work_queue.get(block=True) +- if work_item is not None: +- work_item.run() +- continue +- executor = executor_reference() +- # Exit if: +- # - The interpreter is shutting down OR +- # - The executor that owns the worker has been collected OR +- # - The executor that owns the worker has been shutdown. +- if _shutdown or executor is None or executor._shutdown: +- # Notice other workers +- work_queue.put(None) +- return +- del executor +- except BaseException: +- _base.LOGGER.critical('Exception in worker', exc_info=True) +- +-class ThreadPoolExecutor(_base.Executor): +- def __init__(self, max_workers): +- """Initializes a new ThreadPoolExecutor instance. +- +- Args: +- max_workers: The maximum number of threads that can be used to +- execute the given calls. +- """ +- self._max_workers = max_workers +- self._work_queue = queue.Queue() +- self._threads = set() +- self._shutdown = False +- self._shutdown_lock = threading.Lock() +- +- def submit(self, fn, *args, **kwargs): +- with self._shutdown_lock: +- if self._shutdown: +- raise RuntimeError('cannot schedule new futures after shutdown') +- +- f = _base.Future() +- w = _WorkItem(f, fn, args, kwargs) +- +- self._work_queue.put(w) +- self._adjust_thread_count() +- return f +- submit.__doc__ = _base.Executor.submit.__doc__ +- +- def _adjust_thread_count(self): +- # When the executor gets lost, the weakref callback will wake up +- # the worker threads. +- def weakref_cb(_, q=self._work_queue): +- q.put(None) +- # TODO(bquinlan): Should avoid creating new threads if there are more +- # idle threads than items in the work queue. +- if len(self._threads) < self._max_workers: +- t = threading.Thread(target=_worker, +- args=(weakref.ref(self, weakref_cb), +- self._work_queue)) +- t.daemon = True +- t.start() +- self._threads.add(t) +- _threads_queues[t] = self._work_queue +- +- def shutdown(self, wait=True): +- with self._shutdown_lock: +- self._shutdown = True +- self._work_queue.put(None) +- if wait: +- for t in self._threads: +- t.join() +- shutdown.__doc__ = _base.Executor.shutdown.__doc__ +diff --git a/third_party/pythonfutures/crawl.py b/third_party/pythonfutures/crawl.py +deleted file mode 100755 +index 86e0af7fe..000000000 +--- a/third_party/pythonfutures/crawl.py ++++ /dev/null +@@ -1,74 +0,0 @@ +-"""Compare the speed of downloading URLs sequentially vs. using futures.""" +- +-import functools +-import time +-import timeit +-import sys +- +-try: +- from urllib2 import urlopen +-except ImportError: +- from urllib.request import urlopen +- +-from concurrent.futures import (as_completed, ThreadPoolExecutor, +- ProcessPoolExecutor) +- +-URLS = ['http://www.google.com/', +- 'http://www.apple.com/', +- 'http://www.ibm.com', +- 'http://www.thisurlprobablydoesnotexist.com', +- 'http://www.slashdot.org/', +- 'http://www.python.org/', +- 'http://www.bing.com/', +- 'http://www.facebook.com/', +- 'http://www.yahoo.com/', +- 'http://www.youtube.com/', +- 'http://www.blogger.com/'] +- +-def load_url(url, timeout): +- kwargs = {'timeout': timeout} if sys.version_info >= (2, 6) else {} +- return urlopen(url, **kwargs).read() +- +-def download_urls_sequential(urls, timeout=60): +- url_to_content = {} +- for url in urls: +- try: +- url_to_content[url] = load_url(url, timeout=timeout) +- except: +- pass +- return url_to_content +- +-def download_urls_with_executor(urls, executor, timeout=60): +- try: +- url_to_content = {} +- future_to_url = dict((executor.submit(load_url, url, timeout), url) +- for url in urls) +- +- for future in as_completed(future_to_url): +- try: +- url_to_content[future_to_url[future]] = future.result() +- except: +- pass +- return url_to_content +- finally: +- executor.shutdown() +- +-def main(): +- for name, fn in [('sequential', +- functools.partial(download_urls_sequential, URLS)), +- ('processes', +- functools.partial(download_urls_with_executor, +- URLS, +- ProcessPoolExecutor(10))), +- ('threads', +- functools.partial(download_urls_with_executor, +- URLS, +- ThreadPoolExecutor(10)))]: +- sys.stdout.write('%s: ' % name.ljust(12)) +- start = time.time() +- url_map = fn() +- sys.stdout.write('%.2f seconds (%d of %d downloaded)\n' % +- (time.time() - start, len(url_map), len(URLS))) +- +-if __name__ == '__main__': +- main() +diff --git a/third_party/pythonfutures/docs/conf.py b/third_party/pythonfutures/docs/conf.py +deleted file mode 100755 +index 124cd5183..000000000 +--- a/third_party/pythonfutures/docs/conf.py ++++ /dev/null +@@ -1,194 +0,0 @@ +-# -*- coding: utf-8 -*- +-# +-# futures documentation build configuration file, created by +-# sphinx-quickstart on Wed Jun 3 19:35:34 2009. +-# +-# This file is execfile()d with the current directory set to its containing dir. +-# +-# Note that not all possible configuration values are present in this +-# autogenerated file. +-# +-# All configuration values have a default; values that are commented out +-# serve to show the default. +- +-import sys, os +- +-# If extensions (or modules to document with autodoc) are in another directory, +-# add these directories to sys.path here. If the directory is relative to the +-# documentation root, use os.path.abspath to make it absolute, like shown here. +-#sys.path.append(os.path.abspath('.')) +- +-# -- General configuration ----------------------------------------------------- +- +-# Add any Sphinx extension module names here, as strings. They can be extensions +-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +-extensions = [] +- +-# Add any paths that contain templates here, relative to this directory. +-templates_path = ['_templates'] +- +-# The suffix of source filenames. +-source_suffix = '.rst' +- +-# The encoding of source files. +-#source_encoding = 'utf-8' +- +-# The master toctree document. +-master_doc = 'index' +- +-# General information about the project. +-project = u'futures' +-copyright = u'2009-2011, Brian Quinlan' +- +-# The version info for the project you're documenting, acts as replacement for +-# |version| and |release|, also used in various other places throughout the +-# built documents. +-# +-# The short X.Y version. +-version = '2.1.3' +-# The full version, including alpha/beta/rc tags. +-release = '2.1.3' +- +-# The language for content autogenerated by Sphinx. Refer to documentation +-# for a list of supported languages. +-#language = None +- +-# There are two options for replacing |today|: either, you set today to some +-# non-false value, then it is used: +-#today = '' +-# Else, today_fmt is used as the format for a strftime call. +-#today_fmt = '%B %d, %Y' +- +-# List of documents that shouldn't be included in the build. +-#unused_docs = [] +- +-# List of directories, relative to source directory, that shouldn't be searched +-# for source files. +-exclude_trees = ['_build'] +- +-# The reST default role (used for this markup: `text`) to use for all documents. +-#default_role = None +- +-# If true, '()' will be appended to :func: etc. cross-reference text. +-#add_function_parentheses = True +- +-# If true, the current module name will be prepended to all description +-# unit titles (such as .. function::). +-#add_module_names = True +- +-# If true, sectionauthor and moduleauthor directives will be shown in the +-# output. They are ignored by default. +-#show_authors = False +- +-# The name of the Pygments (syntax highlighting) style to use. +-pygments_style = 'sphinx' +- +-# A list of ignored prefixes for module index sorting. +-#modindex_common_prefix = [] +- +- +-# -- Options for HTML output --------------------------------------------------- +- +-# The theme to use for HTML and HTML Help pages. Major themes that come with +-# Sphinx are currently 'default' and 'sphinxdoc'. +-html_theme = 'default' +- +-# Theme options are theme-specific and customize the look and feel of a theme +-# further. For a list of options available for each theme, see the +-# documentation. +-#html_theme_options = {} +- +-# Add any paths that contain custom themes here, relative to this directory. +-#html_theme_path = [] +- +-# The name for this set of Sphinx documents. If None, it defaults to +-# "<project> v<release> documentation". +-#html_title = None +- +-# A shorter title for the navigation bar. Default is the same as html_title. +-#html_short_title = None +- +-# The name of an image file (relative to this directory) to place at the top +-# of the sidebar. +-#html_logo = None +- +-# The name of an image file (within the static path) to use as favicon of the +-# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +-# pixels large. +-#html_favicon = None +- +-# Add any paths that contain custom static files (such as style sheets) here, +-# relative to this directory. They are copied after the builtin static files, +-# so a file named "default.css" will overwrite the builtin "default.css". +-html_static_path = ['_static'] +- +-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +-# using the given strftime format. +-#html_last_updated_fmt = '%b %d, %Y' +- +-# If true, SmartyPants will be used to convert quotes and dashes to +-# typographically correct entities. +-#html_use_smartypants = True +- +-# Custom sidebar templates, maps document names to template names. +-#html_sidebars = {} +- +-# Additional templates that should be rendered to pages, maps page names to +-# template names. +-#html_additional_pages = {} +- +-# If false, no module index is generated. +-#html_use_modindex = True +- +-# If false, no index is generated. +-#html_use_index = True +- +-# If true, the index is split into individual pages for each letter. +-#html_split_index = False +- +-# If true, links to the reST sources are added to the pages. +-#html_show_sourcelink = True +- +-# If true, an OpenSearch description file will be output, and all pages will +-# contain a <link> tag referring to it. The value of this option must be the +-# base URL from which the finished HTML is served. +-#html_use_opensearch = '' +- +-# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). +-#html_file_suffix = '' +- +-# Output file base name for HTML help builder. +-htmlhelp_basename = 'futuresdoc' +- +- +-# -- Options for LaTeX output -------------------------------------------------- +- +-# The paper size ('letter' or 'a4'). +-#latex_paper_size = 'letter' +- +-# The font size ('10pt', '11pt' or '12pt'). +-#latex_font_size = '10pt' +- +-# Grouping the document tree into LaTeX files. List of tuples +-# (source start file, target name, title, author, documentclass [howto/manual]). +-latex_documents = [ +- ('index', 'futures.tex', u'futures Documentation', +- u'Brian Quinlan', 'manual'), +-] +- +-# The name of an image file (relative to this directory) to place at the top of +-# the title page. +-#latex_logo = None +- +-# For "manual" documents, if this is true, then toplevel headings are parts, +-# not chapters. +-#latex_use_parts = False +- +-# Additional stuff for the LaTeX preamble. +-#latex_preamble = '' +- +-# Documents to append as an appendix to all manuals. +-#latex_appendices = [] +- +-# If false, no module index is generated. +-#latex_use_modindex = True +diff --git a/third_party/pythonfutures/docs/index.rst b/third_party/pythonfutures/docs/index.rst +deleted file mode 100755 +index 525ce6ab3..000000000 +--- a/third_party/pythonfutures/docs/index.rst ++++ /dev/null +@@ -1,345 +0,0 @@ +-:mod:`concurrent.futures` --- Asynchronous computation +-====================================================== +- +-.. module:: concurrent.futures +- :synopsis: Execute computations asynchronously using threads or processes. +- +-The :mod:`concurrent.futures` module provides a high-level interface for +-asynchronously executing callables. +- +-The asynchronous execution can be be performed by threads using +-:class:`ThreadPoolExecutor` or seperate processes using +-:class:`ProcessPoolExecutor`. Both implement the same interface, which is +-defined by the abstract :class:`Executor` class. +- +-Executor Objects +----------------- +- +-:class:`Executor` is an abstract class that provides methods to execute calls +-asynchronously. It should not be used directly, but through its two +-subclasses: :class:`ThreadPoolExecutor` and :class:`ProcessPoolExecutor`. +- +-.. method:: Executor.submit(fn, *args, **kwargs) +- +- Schedules the callable to be executed as *fn*(*\*args*, *\*\*kwargs*) and +- returns a :class:`Future` representing the execution of the callable. +- +-:: +- +- with ThreadPoolExecutor(max_workers=1) as executor: +- future = executor.submit(pow, 323, 1235) +- print(future.result()) +- +-.. method:: Executor.map(func, *iterables, timeout=None) +- +- Equivalent to map(*func*, *\*iterables*) but func is executed asynchronously +- and several calls to *func* may be made concurrently. The returned iterator +- raises a :exc:`TimeoutError` if :meth:`__next__()` is called and the result +- isn't available after *timeout* seconds from the original call to +- :meth:`map()`. *timeout* can be an int or float. If *timeout* is not +- specified or ``None`` then there is no limit to the wait time. If a call +- raises an exception then that exception will be raised when its value is +- retrieved from the iterator. +- +-.. method:: Executor.shutdown(wait=True) +- +- Signal the executor that it should free any resources that it is using when +- the currently pending futures are done executing. Calls to +- :meth:`Executor.submit` and :meth:`Executor.map` made after shutdown will +- raise :exc:`RuntimeError`. +- +- If *wait* is `True` then this method will not return until all the pending +- futures are done executing and the resources associated with the executor +- have been freed. If *wait* is `False` then this method will return +- immediately and the resources associated with the executor will be freed +- when all pending futures are done executing. Regardless of the value of +- *wait*, the entire Python program will not exit until all pending futures +- are done executing. +- +- You can avoid having to call this method explicitly if you use the `with` +- statement, which will shutdown the `Executor` (waiting as if +- `Executor.shutdown` were called with *wait* set to `True`): +- +-:: +- +- import shutil +- with ThreadPoolExecutor(max_workers=4) as e: +- e.submit(shutil.copy, 'src1.txt', 'dest1.txt') +- e.submit(shutil.copy, 'src2.txt', 'dest2.txt') +- e.submit(shutil.copy, 'src3.txt', 'dest3.txt') +- e.submit(shutil.copy, 'src3.txt', 'dest4.txt') +- +- +-ThreadPoolExecutor Objects +--------------------------- +- +-The :class:`ThreadPoolExecutor` class is an :class:`Executor` subclass that uses +-a pool of threads to execute calls asynchronously. +- +-Deadlock can occur when the callable associated with a :class:`Future` waits on +-the results of another :class:`Future`. For example: +- +-:: +- +- import time +- def wait_on_b(): +- time.sleep(5) +- print(b.result()) # b will never complete because it is waiting on a. +- return 5 +- +- def wait_on_a(): +- time.sleep(5) +- print(a.result()) # a will never complete because it is waiting on b. +- return 6 +- +- +- executor = ThreadPoolExecutor(max_workers=2) +- a = executor.submit(wait_on_b) +- b = executor.submit(wait_on_a) +- +-And: +- +-:: +- +- def wait_on_future(): +- f = executor.submit(pow, 5, 2) +- # This will never complete because there is only one worker thread and +- # it is executing this function. +- print(f.result()) +- +- executor = ThreadPoolExecutor(max_workers=1) +- executor.submit(wait_on_future) +- +-.. class:: ThreadPoolExecutor(max_workers) +- +- Executes calls asynchronously using at pool of at most *max_workers* threads. +- +-.. _threadpoolexecutor-example: +- +-ThreadPoolExecutor Example +-^^^^^^^^^^^^^^^^^^^^^^^^^^ +-:: +- +- from concurrent import futures +- import urllib.request +- +- URLS = ['http://www.foxnews.com/', +- 'http://www.cnn.com/', +- 'http://europe.wsj.com/', +- 'http://www.bbc.co.uk/', +- 'http://some-made-up-domain.com/'] +- +- def load_url(url, timeout): +- return urllib.request.urlopen(url, timeout=timeout).read() +- +- with futures.ThreadPoolExecutor(max_workers=5) as executor: +- future_to_url = dict((executor.submit(load_url, url, 60), url) +- for url in URLS) +- +- for future in futures.as_completed(future_to_url): +- url = future_to_url[future] +- if future.exception() is not None: +- print('%r generated an exception: %s' % (url, +- future.exception())) +- else: +- print('%r page is %d bytes' % (url, len(future.result()))) +- +-ProcessPoolExecutor Objects +---------------------------- +- +-The :class:`ProcessPoolExecutor` class is an :class:`Executor` subclass that +-uses a pool of processes to execute calls asynchronously. +-:class:`ProcessPoolExecutor` uses the :mod:`multiprocessing` module, which +-allows it to side-step the :term:`Global Interpreter Lock` but also means that +-only picklable objects can be executed and returned. +- +-Calling :class:`Executor` or :class:`Future` methods from a callable submitted +-to a :class:`ProcessPoolExecutor` will result in deadlock. +- +-.. class:: ProcessPoolExecutor(max_workers=None) +- +- Executes calls asynchronously using a pool of at most *max_workers* +- processes. If *max_workers* is ``None`` or not given then as many worker +- processes will be created as the machine has processors. +- +-.. _processpoolexecutor-example: +- +-ProcessPoolExecutor Example +-^^^^^^^^^^^^^^^^^^^^^^^^^^^ +-:: +- +- import math +- +- PRIMES = [ +- 112272535095293, +- 112582705942171, +- 112272535095293, +- 115280095190773, +- 115797848077099, +- 1099726899285419] +- +- def is_prime(n): +- if n % 2 == 0: +- return False +- +- sqrt_n = int(math.floor(math.sqrt(n))) +- for i in range(3, sqrt_n + 1, 2): +- if n % i == 0: +- return False +- return True +- +- def main(): +- with futures.ProcessPoolExecutor() as executor: +- for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)): +- print('%d is prime: %s' % (number, prime)) +- +- if __name__ == '__main__': +- main() +- +-Future Objects +--------------- +- +-The :class:`Future` class encapulates the asynchronous execution of a callable. +-:class:`Future` instances are created by :meth:`Executor.submit`. +- +-.. method:: Future.cancel() +- +- Attempt to cancel the call. If the call is currently being executed then +- it cannot be cancelled and the method will return `False`, otherwise the call +- will be cancelled and the method will return `True`. +- +-.. method:: Future.cancelled() +- +- Return `True` if the call was successfully cancelled. +- +-.. method:: Future.running() +- +- Return `True` if the call is currently being executed and cannot be +- cancelled. +- +-.. method:: Future.done() +- +- Return `True` if the call was successfully cancelled or finished running. +- +-.. method:: Future.result(timeout=None) +- +- Return the value returned by the call. If the call hasn't yet completed then +- this method will wait up to *timeout* seconds. If the call hasn't completed +- in *timeout* seconds then a :exc:`TimeoutError` will be raised. *timeout* can +- be an int or float.If *timeout* is not specified or ``None`` then there is no +- limit to the wait time. +- +- If the future is cancelled before completing then :exc:`CancelledError` will +- be raised. +- +- If the call raised then this method will raise the same exception. +- +-.. method:: Future.exception(timeout=None) +- +- Return the exception raised by the call. If the call hasn't yet completed +- then this method will wait up to *timeout* seconds. If the call hasn't +- completed in *timeout* seconds then a :exc:`TimeoutError` will be raised. +- *timeout* can be an int or float. If *timeout* is not specified or ``None`` +- then there is no limit to the wait time. +- +- If the future is cancelled before completing then :exc:`CancelledError` will +- be raised. +- +- If the call completed without raising then ``None`` is returned. +- +-.. method:: Future.add_done_callback(fn) +- +- Attaches the callable *fn* to the future. *fn* will be called, with the +- future as its only argument, when the future is cancelled or finishes +- running. +- +- Added callables are called in the order that they were added and are always +- called in a thread belonging to the process that added them. If the callable +- raises an :exc:`Exception` then it will be logged and ignored. If the +- callable raises another :exc:`BaseException` then the behavior is not +- defined. +- +- If the future has already completed or been cancelled then *fn* will be +- called immediately. +- +-Internal Future Methods +-^^^^^^^^^^^^^^^^^^^^^^^ +- +-The following :class:`Future` methods are meant for use in unit tests and +-:class:`Executor` implementations. +- +-.. method:: Future.set_running_or_notify_cancel() +- +- This method should only be called by :class:`Executor` implementations before +- executing the work associated with the :class:`Future` and by unit tests. +- +- If the method returns `False` then the :class:`Future` was cancelled i.e. +- :meth:`Future.cancel` was called and returned `True`. Any threads waiting +- on the :class:`Future` completing (i.e. through :func:`as_completed` or +- :func:`wait`) will be woken up. +- +- If the method returns `True` then the :class:`Future` was not cancelled +- and has been put in the running state i.e. calls to +- :meth:`Future.running` will return `True`. +- +- This method can only be called once and cannot be called after +- :meth:`Future.set_result` or :meth:`Future.set_exception` have been +- called. +- +-.. method:: Future.set_result(result) +- +- Sets the result of the work associated with the :class:`Future` to *result*. +- +- This method should only be used by Executor implementations and unit tests. +- +-.. method:: Future.set_exception(exception) +- +- Sets the result of the work associated with the :class:`Future` to the +- :class:`Exception` *exception*. +- +- This method should only be used by Executor implementations and unit tests. +- +-Module Functions +----------------- +- +-.. function:: wait(fs, timeout=None, return_when=ALL_COMPLETED) +- +- Wait for the :class:`Future` instances (possibly created by different +- :class:`Executor` instances) given by *fs* to complete. Returns a named +- 2-tuple of sets. The first set, named "done", contains the futures that +- completed (finished or were cancelled) before the wait completed. The second +- set, named "not_done", contains uncompleted futures. +- +- *timeout* can be used to control the maximum number of seconds to wait before +- returning. *timeout* can be an int or float. If *timeout* is not specified or +- ``None`` then there is no limit to the wait time. +- +- *return_when* indicates when this function should return. It must be one of +- the following constants: +- +- +-----------------------------+----------------------------------------+ +- | Constant | Description | +- +=============================+========================================+ +- | :const:`FIRST_COMPLETED` | The function will return when any | +- | | future finishes or is cancelled. | +- +-----------------------------+----------------------------------------+ +- | :const:`FIRST_EXCEPTION` | The function will return when any | +- | | future finishes by raising an | +- | | exception. If no future raises an | +- | | exception then it is equivalent to | +- | | `ALL_COMPLETED`. | +- +-----------------------------+----------------------------------------+ +- | :const:`ALL_COMPLETED` | The function will return when all | +- | | futures finish or are cancelled. | +- +-----------------------------+----------------------------------------+ +- +-.. function:: as_completed(fs, timeout=None) +- +- Returns an iterator over the :class:`Future` instances (possibly created +- by different :class:`Executor` instances) given by *fs* that yields futures +- as they complete (finished or were cancelled). Any futures that completed +- before :func:`as_completed()` was called will be yielded first. The returned +- iterator raises a :exc:`TimeoutError` if :meth:`__next__()` is called and +- the result isn't available after *timeout* seconds from the original call +- to :func:`as_completed()`. *timeout* can be an int or float. If *timeout* +- is not specified or ``None`` then there is no limit to the wait time. +diff --git a/third_party/pythonfutures/docs/make.bat b/third_party/pythonfutures/docs/make.bat +deleted file mode 100755 +index 3e8021b56..000000000 +--- a/third_party/pythonfutures/docs/make.bat ++++ /dev/null +@@ -1,112 +0,0 @@ +-@ECHO OFF +- +-REM Command file for Sphinx documentation +- +-set SPHINXBUILD=sphinx-build +-set ALLSPHINXOPTS=-d _build/doctrees %SPHINXOPTS% . +-if NOT "%PAPER%" == "" ( +- set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% +-) +- +-if "%1" == "" goto help +- +-if "%1" == "help" ( +- :help +- echo.Please use `make ^<target^>` where ^<target^> is one of +- echo. html to make standalone HTML files +- echo. dirhtml to make HTML files named index.html in directories +- echo. pickle to make pickle files +- echo. json to make JSON files +- echo. htmlhelp to make HTML files and a HTML help project +- echo. qthelp to make HTML files and a qthelp project +- echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter +- echo. changes to make an overview over all changed/added/deprecated items +- echo. linkcheck to check all external links for integrity +- echo. doctest to run all doctests embedded in the documentation if enabled +- goto end +-) +- +-if "%1" == "clean" ( +- for /d %%i in (_build\*) do rmdir /q /s %%i +- del /q /s _build\* +- goto end +-) +- +-if "%1" == "html" ( +- %SPHINXBUILD% -b html %ALLSPHINXOPTS% _build/html +- echo. +- echo.Build finished. The HTML pages are in _build/html. +- goto end +-) +- +-if "%1" == "dirhtml" ( +- %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% _build/dirhtml +- echo. +- echo.Build finished. The HTML pages are in _build/dirhtml. +- goto end +-) +- +-if "%1" == "pickle" ( +- %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% _build/pickle +- echo. +- echo.Build finished; now you can process the pickle files. +- goto end +-) +- +-if "%1" == "json" ( +- %SPHINXBUILD% -b json %ALLSPHINXOPTS% _build/json +- echo. +- echo.Build finished; now you can process the JSON files. +- goto end +-) +- +-if "%1" == "htmlhelp" ( +- %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% _build/htmlhelp +- echo. +- echo.Build finished; now you can run HTML Help Workshop with the ^ +-.hhp project file in _build/htmlhelp. +- goto end +-) +- +-if "%1" == "qthelp" ( +- %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% _build/qthelp +- echo. +- echo.Build finished; now you can run "qcollectiongenerator" with the ^ +-.qhcp project file in _build/qthelp, like this: +- echo.^> qcollectiongenerator _build\qthelp\futures.qhcp +- echo.To view the help file: +- echo.^> assistant -collectionFile _build\qthelp\futures.ghc +- goto end +-) +- +-if "%1" == "latex" ( +- %SPHINXBUILD% -b latex %ALLSPHINXOPTS% _build/latex +- echo. +- echo.Build finished; the LaTeX files are in _build/latex. +- goto end +-) +- +-if "%1" == "changes" ( +- %SPHINXBUILD% -b changes %ALLSPHINXOPTS% _build/changes +- echo. +- echo.The overview file is in _build/changes. +- goto end +-) +- +-if "%1" == "linkcheck" ( +- %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% _build/linkcheck +- echo. +- echo.Link check complete; look for any errors in the above output ^ +-or in _build/linkcheck/output.txt. +- goto end +-) +- +-if "%1" == "doctest" ( +- %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% _build/doctest +- echo. +- echo.Testing of doctests in the sources finished, look at the ^ +-results in _build/doctest/output.txt. +- goto end +-) +- +-:end +diff --git a/third_party/pythonfutures/futures/__init__.py b/third_party/pythonfutures/futures/__init__.py +deleted file mode 100755 +index 8f8b23481..000000000 +--- a/third_party/pythonfutures/futures/__init__.py ++++ /dev/null +@@ -1,24 +0,0 @@ +-# Copyright 2009 Brian Quinlan. All Rights Reserved. +-# Licensed to PSF under a Contributor Agreement. +- +-"""Execute computations asynchronously using threads or processes.""" +- +-import warnings +- +-from concurrent.futures import (FIRST_COMPLETED, +- FIRST_EXCEPTION, +- ALL_COMPLETED, +- CancelledError, +- TimeoutError, +- Future, +- Executor, +- wait, +- as_completed, +- ProcessPoolExecutor, +- ThreadPoolExecutor) +- +-__author__ = 'Brian Quinlan (brian@sweetapp.com)' +- +-warnings.warn('The futures package has been deprecated. ' +- 'Use the concurrent.futures package instead.', +- DeprecationWarning) +diff --git a/third_party/pythonfutures/futures/process.py b/third_party/pythonfutures/futures/process.py +deleted file mode 100755 +index e9d37b16c..000000000 +--- a/third_party/pythonfutures/futures/process.py ++++ /dev/null +@@ -1 +0,0 @@ +-from concurrent.futures import ProcessPoolExecutor +diff --git a/third_party/pythonfutures/futures/thread.py b/third_party/pythonfutures/futures/thread.py +deleted file mode 100755 +index f6bd05de6..000000000 +--- a/third_party/pythonfutures/futures/thread.py ++++ /dev/null +@@ -1 +0,0 @@ +-from concurrent.futures import ThreadPoolExecutor +diff --git a/third_party/pythonfutures/primes.py b/third_party/pythonfutures/primes.py +deleted file mode 100755 +index 0da2b3e64..000000000 +--- a/third_party/pythonfutures/primes.py ++++ /dev/null +@@ -1,50 +0,0 @@ +-from __future__ import with_statement +-import math +-import time +-import sys +- +-from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor +- +-PRIMES = [ +- 112272535095293, +- 112582705942171, +- 112272535095293, +- 115280095190773, +- 115797848077099, +- 117450548693743, +- 993960000099397] +- +-def is_prime(n): +- if n % 2 == 0: +- return False +- +- sqrt_n = int(math.floor(math.sqrt(n))) +- for i in range(3, sqrt_n + 1, 2): +- if n % i == 0: +- return False +- return True +- +-def sequential(): +- return list(map(is_prime, PRIMES)) +- +-def with_process_pool_executor(): +- with ProcessPoolExecutor(10) as executor: +- return list(executor.map(is_prime, PRIMES)) +- +-def with_thread_pool_executor(): +- with ThreadPoolExecutor(10) as executor: +- return list(executor.map(is_prime, PRIMES)) +- +-def main(): +- for name, fn in [('sequential', sequential), +- ('processes', with_process_pool_executor), +- ('threads', with_thread_pool_executor)]: +- sys.stdout.write('%s: ' % name.ljust(12)) +- start = time.time() +- if fn() != [True] * len(PRIMES): +- sys.stdout.write('failed\n') +- else: +- sys.stdout.write('%.2f seconds\n' % (time.time() - start)) +- +-if __name__ == '__main__': +- main() +diff --git a/third_party/pythonfutures/setup.cfg b/third_party/pythonfutures/setup.cfg +deleted file mode 100755 +index 0a9f4f521..000000000 +--- a/third_party/pythonfutures/setup.cfg ++++ /dev/null +@@ -1,6 +0,0 @@ +-[build_sphinx] +-source-dir = docs +-build-dir = build/sphinx +- +-[upload_docs] +-upload-dir = build/sphinx/html +diff --git a/third_party/pythonfutures/setup.py b/third_party/pythonfutures/setup.py +deleted file mode 100755 +index c08461eda..000000000 +--- a/third_party/pythonfutures/setup.py ++++ /dev/null +@@ -1,33 +0,0 @@ +-#!/usr/bin/env python +-import sys +- +-extras = {} +-try: +- from setuptools import setup +- extras['zip_safe'] = False +- if sys.version_info < (2, 6): +- extras['install_requires'] = ['multiprocessing'] +-except ImportError: +- from distutils.core import setup +- +-setup(name='futures', +- version='2.1.4', +- description='Backport of the concurrent.futures package from Python 3.2', +- author='Brian Quinlan', +- author_email='brian@sweetapp.com', +- maintainer='Alex Gronholm', +- maintainer_email='alex.gronholm+pypi@nextday.fi', +- url='http://code.google.com/p/pythonfutures', +- download_url='http://pypi.python.org/pypi/futures/', +- packages=['futures', 'concurrent', 'concurrent.futures'], +- license='BSD', +- classifiers=['License :: OSI Approved :: BSD License', +- 'Development Status :: 5 - Production/Stable', +- 'Intended Audience :: Developers', +- 'Programming Language :: Python :: 2.5', +- 'Programming Language :: Python :: 2.6', +- 'Programming Language :: Python :: 2.7', +- 'Programming Language :: Python :: 3', +- 'Programming Language :: Python :: 3.1'], +- **extras +- ) +diff --git a/third_party/pythonfutures/test_futures.py b/third_party/pythonfutures/test_futures.py +deleted file mode 100755 +index dd7fd3e69..000000000 +--- a/third_party/pythonfutures/test_futures.py ++++ /dev/null +@@ -1,723 +0,0 @@ +-from __future__ import with_statement +-import os +-import subprocess +-import sys +-import threading +-import functools +-import contextlib +-import logging +-import re +-import time +- +-from concurrent import futures +-from concurrent.futures._base import ( +- PENDING, RUNNING, CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED, Future) +- +-try: +- import unittest2 as unittest +-except ImportError: +- import unittest +- +-try: +- from StringIO import StringIO +-except ImportError: +- from io import StringIO +- +-try: +- from test import test_support +-except ImportError: +- from test import support as test_support +- +-try: +- next +-except NameError: +- next = lambda x: x.next() +- +- +-def reap_threads(func): +- """Use this function when threads are being used. This will +- ensure that the threads are cleaned up even when the test fails. +- If threading is unavailable this function does nothing. +- """ +- @functools.wraps(func) +- def decorator(*args): +- key = test_support.threading_setup() +- try: +- return func(*args) +- finally: +- test_support.threading_cleanup(*key) +- return decorator +- +- +-# Executing the interpreter in a subprocess +-def _assert_python(expected_success, *args, **env_vars): +- cmd_line = [sys.executable] +- if not env_vars: +- cmd_line.append('-E') +- # Need to preserve the original environment, for in-place testing of +- # shared library builds. +- env = os.environ.copy() +- # But a special flag that can be set to override -- in this case, the +- # caller is responsible to pass the full environment. +- if env_vars.pop('__cleanenv', None): +- env = {} +- env.update(env_vars) +- cmd_line.extend(args) +- p = subprocess.Popen(cmd_line, stdin=subprocess.PIPE, +- stdout=subprocess.PIPE, stderr=subprocess.PIPE, +- env=env) +- try: +- out, err = p.communicate() +- finally: +- subprocess._cleanup() +- p.stdout.close() +- p.stderr.close() +- rc = p.returncode +- err = strip_python_stderr(err) +- if (rc and expected_success) or (not rc and not expected_success): +- raise AssertionError( +- "Process return code is %d, " +- "stderr follows:\n%s" % (rc, err.decode('ascii', 'ignore'))) +- return rc, out, err +- +- +-def assert_python_ok(*args, **env_vars): +- """ +- Assert that running the interpreter with `args` and optional environment +- variables `env_vars` is ok and return a (return code, stdout, stderr) tuple. +- """ +- return _assert_python(True, *args, **env_vars) +- +- +-def strip_python_stderr(stderr): +- """Strip the stderr of a Python process from potential debug output +- emitted by the interpreter. +- +- This will typically be run on the result of the communicate() method +- of a subprocess.Popen object. +- """ +- stderr = re.sub(r"\[\d+ refs\]\r?\n?$".encode(), "".encode(), stderr).strip() +- return stderr +- +- +-@contextlib.contextmanager +-def captured_stderr(): +- """Return a context manager used by captured_stdout/stdin/stderr +- that temporarily replaces the sys stream *stream_name* with a StringIO.""" +- logging_stream = StringIO() +- handler = logging.StreamHandler(logging_stream) +- logging.root.addHandler(handler) +- +- try: +- yield logging_stream +- finally: +- logging.root.removeHandler(handler) +- +- +-def create_future(state=PENDING, exception=None, result=None): +- f = Future() +- f._state = state +- f._exception = exception +- f._result = result +- return f +- +- +-PENDING_FUTURE = create_future(state=PENDING) +-RUNNING_FUTURE = create_future(state=RUNNING) +-CANCELLED_FUTURE = create_future(state=CANCELLED) +-CANCELLED_AND_NOTIFIED_FUTURE = create_future(state=CANCELLED_AND_NOTIFIED) +-EXCEPTION_FUTURE = create_future(state=FINISHED, exception=IOError()) +-SUCCESSFUL_FUTURE = create_future(state=FINISHED, result=42) +- +- +-def mul(x, y): +- return x * y +- +- +-def sleep_and_raise(t): +- time.sleep(t) +- raise Exception('this is an exception') +- +-def sleep_and_print(t, msg): +- time.sleep(t) +- print(msg) +- sys.stdout.flush() +- +- +-class ExecutorMixin: +- worker_count = 5 +- +- def setUp(self): +- self.t1 = time.time() +- try: +- self.executor = self.executor_type(max_workers=self.worker_count) +- except NotImplementedError: +- e = sys.exc_info()[1] +- self.skipTest(str(e)) +- self._prime_executor() +- +- def tearDown(self): +- self.executor.shutdown(wait=True) +- dt = time.time() - self.t1 +- if test_support.verbose: +- print("%.2fs" % dt) +- self.assertLess(dt, 60, "synchronization issue: test lasted too long") +- +- def _prime_executor(self): +- # Make sure that the executor is ready to do work before running the +- # tests. This should reduce the probability of timeouts in the tests. +- futures = [self.executor.submit(time.sleep, 0.1) +- for _ in range(self.worker_count)] +- +- for f in futures: +- f.result() +- +- +-class ThreadPoolMixin(ExecutorMixin): +- executor_type = futures.ThreadPoolExecutor +- +- +-class ProcessPoolMixin(ExecutorMixin): +- executor_type = futures.ProcessPoolExecutor +- +- +-class ExecutorShutdownTest(unittest.TestCase): +- def test_run_after_shutdown(self): +- self.executor.shutdown() +- self.assertRaises(RuntimeError, +- self.executor.submit, +- pow, 2, 5) +- +- def test_interpreter_shutdown(self): +- # Test the atexit hook for shutdown of worker threads and processes +- rc, out, err = assert_python_ok('-c', """if 1: +- from concurrent.futures import %s +- from time import sleep +- from test_futures import sleep_and_print +- t = %s(5) +- t.submit(sleep_and_print, 1.0, "apple") +- """ % (self.executor_type.__name__, self.executor_type.__name__)) +- # Errors in atexit hooks don't change the process exit code, check +- # stderr manually. +- self.assertFalse(err) +- self.assertEqual(out.strip(), "apple".encode()) +- +- def test_hang_issue12364(self): +- fs = [self.executor.submit(time.sleep, 0.1) for _ in range(50)] +- self.executor.shutdown() +- for f in fs: +- f.result() +- +- +-class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest): +- def _prime_executor(self): +- pass +- +- def test_threads_terminate(self): +- self.executor.submit(mul, 21, 2) +- self.executor.submit(mul, 6, 7) +- self.executor.submit(mul, 3, 14) +- self.assertEqual(len(self.executor._threads), 3) +- self.executor.shutdown() +- for t in self.executor._threads: +- t.join() +- +- def test_context_manager_shutdown(self): +- with futures.ThreadPoolExecutor(max_workers=5) as e: +- executor = e +- self.assertEqual(list(e.map(abs, range(-5, 5))), +- [5, 4, 3, 2, 1, 0, 1, 2, 3, 4]) +- +- for t in executor._threads: +- t.join() +- +- def test_del_shutdown(self): +- executor = futures.ThreadPoolExecutor(max_workers=5) +- executor.map(abs, range(-5, 5)) +- threads = executor._threads +- del executor +- +- for t in threads: +- t.join() +- +- +-class ProcessPoolShutdownTest(ProcessPoolMixin, ExecutorShutdownTest): +- def _prime_executor(self): +- pass +- +- def test_processes_terminate(self): +- self.executor.submit(mul, 21, 2) +- self.executor.submit(mul, 6, 7) +- self.executor.submit(mul, 3, 14) +- self.assertEqual(len(self.executor._processes), 5) +- processes = self.executor._processes +- self.executor.shutdown() +- +- for p in processes: +- p.join() +- +- def test_context_manager_shutdown(self): +- with futures.ProcessPoolExecutor(max_workers=5) as e: +- processes = e._processes +- self.assertEqual(list(e.map(abs, range(-5, 5))), +- [5, 4, 3, 2, 1, 0, 1, 2, 3, 4]) +- +- for p in processes: +- p.join() +- +- def test_del_shutdown(self): +- executor = futures.ProcessPoolExecutor(max_workers=5) +- list(executor.map(abs, range(-5, 5))) +- queue_management_thread = executor._queue_management_thread +- processes = executor._processes +- del executor +- +- queue_management_thread.join() +- for p in processes: +- p.join() +- +- +-class WaitTests(unittest.TestCase): +- +- def test_first_completed(self): +- future1 = self.executor.submit(mul, 21, 2) +- future2 = self.executor.submit(time.sleep, 1.5) +- +- done, not_done = futures.wait( +- [CANCELLED_FUTURE, future1, future2], +- return_when=futures.FIRST_COMPLETED) +- +- self.assertEqual(set([future1]), done) +- self.assertEqual(set([CANCELLED_FUTURE, future2]), not_done) +- +- def test_first_completed_some_already_completed(self): +- future1 = self.executor.submit(time.sleep, 1.5) +- +- finished, pending = futures.wait( +- [CANCELLED_AND_NOTIFIED_FUTURE, SUCCESSFUL_FUTURE, future1], +- return_when=futures.FIRST_COMPLETED) +- +- self.assertEqual( +- set([CANCELLED_AND_NOTIFIED_FUTURE, SUCCESSFUL_FUTURE]), +- finished) +- self.assertEqual(set([future1]), pending) +- +- def test_first_exception(self): +- future1 = self.executor.submit(mul, 2, 21) +- future2 = self.executor.submit(sleep_and_raise, 1.5) +- future3 = self.executor.submit(time.sleep, 3) +- +- finished, pending = futures.wait( +- [future1, future2, future3], +- return_when=futures.FIRST_EXCEPTION) +- +- self.assertEqual(set([future1, future2]), finished) +- self.assertEqual(set([future3]), pending) +- +- def test_first_exception_some_already_complete(self): +- future1 = self.executor.submit(divmod, 21, 0) +- future2 = self.executor.submit(time.sleep, 1.5) +- +- finished, pending = futures.wait( +- [SUCCESSFUL_FUTURE, +- CANCELLED_FUTURE, +- CANCELLED_AND_NOTIFIED_FUTURE, +- future1, future2], +- return_when=futures.FIRST_EXCEPTION) +- +- self.assertEqual(set([SUCCESSFUL_FUTURE, +- CANCELLED_AND_NOTIFIED_FUTURE, +- future1]), finished) +- self.assertEqual(set([CANCELLED_FUTURE, future2]), pending) +- +- def test_first_exception_one_already_failed(self): +- future1 = self.executor.submit(time.sleep, 2) +- +- finished, pending = futures.wait( +- [EXCEPTION_FUTURE, future1], +- return_when=futures.FIRST_EXCEPTION) +- +- self.assertEqual(set([EXCEPTION_FUTURE]), finished) +- self.assertEqual(set([future1]), pending) +- +- def test_all_completed(self): +- future1 = self.executor.submit(divmod, 2, 0) +- future2 = self.executor.submit(mul, 2, 21) +- +- finished, pending = futures.wait( +- [SUCCESSFUL_FUTURE, +- CANCELLED_AND_NOTIFIED_FUTURE, +- EXCEPTION_FUTURE, +- future1, +- future2], +- return_when=futures.ALL_COMPLETED) +- +- self.assertEqual(set([SUCCESSFUL_FUTURE, +- CANCELLED_AND_NOTIFIED_FUTURE, +- EXCEPTION_FUTURE, +- future1, +- future2]), finished) +- self.assertEqual(set(), pending) +- +- def test_timeout(self): +- future1 = self.executor.submit(mul, 6, 7) +- future2 = self.executor.submit(time.sleep, 3) +- +- finished, pending = futures.wait( +- [CANCELLED_AND_NOTIFIED_FUTURE, +- EXCEPTION_FUTURE, +- SUCCESSFUL_FUTURE, +- future1, future2], +- timeout=1.5, +- return_when=futures.ALL_COMPLETED) +- +- self.assertEqual(set([CANCELLED_AND_NOTIFIED_FUTURE, +- EXCEPTION_FUTURE, +- SUCCESSFUL_FUTURE, +- future1]), finished) +- self.assertEqual(set([future2]), pending) +- +- +-class ThreadPoolWaitTests(ThreadPoolMixin, WaitTests): +- +- def test_pending_calls_race(self): +- # Issue #14406: multi-threaded race condition when waiting on all +- # futures. +- event = threading.Event() +- def future_func(): +- event.wait() +- oldswitchinterval = sys.getcheckinterval() +- sys.setcheckinterval(1) +- try: +- fs = set(self.executor.submit(future_func) for i in range(100)) +- event.set() +- futures.wait(fs, return_when=futures.ALL_COMPLETED) +- finally: +- sys.setcheckinterval(oldswitchinterval) +- +- +-class ProcessPoolWaitTests(ProcessPoolMixin, WaitTests): +- pass +- +- +-class AsCompletedTests(unittest.TestCase): +- # TODO(brian@sweetapp.com): Should have a test with a non-zero timeout. +- def test_no_timeout(self): +- future1 = self.executor.submit(mul, 2, 21) +- future2 = self.executor.submit(mul, 7, 6) +- +- completed = set(futures.as_completed( +- [CANCELLED_AND_NOTIFIED_FUTURE, +- EXCEPTION_FUTURE, +- SUCCESSFUL_FUTURE, +- future1, future2])) +- self.assertEqual(set( +- [CANCELLED_AND_NOTIFIED_FUTURE, +- EXCEPTION_FUTURE, +- SUCCESSFUL_FUTURE, +- future1, future2]), +- completed) +- +- def test_zero_timeout(self): +- future1 = self.executor.submit(time.sleep, 2) +- completed_futures = set() +- try: +- for future in futures.as_completed( +- [CANCELLED_AND_NOTIFIED_FUTURE, +- EXCEPTION_FUTURE, +- SUCCESSFUL_FUTURE, +- future1], +- timeout=0): +- completed_futures.add(future) +- except futures.TimeoutError: +- pass +- +- self.assertEqual(set([CANCELLED_AND_NOTIFIED_FUTURE, +- EXCEPTION_FUTURE, +- SUCCESSFUL_FUTURE]), +- completed_futures) +- +- +-class ThreadPoolAsCompletedTests(ThreadPoolMixin, AsCompletedTests): +- pass +- +- +-class ProcessPoolAsCompletedTests(ProcessPoolMixin, AsCompletedTests): +- pass +- +- +-class ExecutorTest(unittest.TestCase): +- # Executor.shutdown() and context manager usage is tested by +- # ExecutorShutdownTest. +- def test_submit(self): +- future = self.executor.submit(pow, 2, 8) +- self.assertEqual(256, future.result()) +- +- def test_submit_keyword(self): +- future = self.executor.submit(mul, 2, y=8) +- self.assertEqual(16, future.result()) +- +- def test_map(self): +- self.assertEqual( +- list(self.executor.map(pow, range(10), range(10))), +- list(map(pow, range(10), range(10)))) +- +- def test_map_exception(self): +- i = self.executor.map(divmod, [1, 1, 1, 1], [2, 3, 0, 5]) +- self.assertEqual(next(i), (0, 1)) +- self.assertEqual(next(i), (0, 1)) +- self.assertRaises(ZeroDivisionError, next, i) +- +- def test_map_timeout(self): +- results = [] +- try: +- for i in self.executor.map(time.sleep, +- [0, 0, 3], +- timeout=1.5): +- results.append(i) +- except futures.TimeoutError: +- pass +- else: +- self.fail('expected TimeoutError') +- +- self.assertEqual([None, None], results) +- +- +-class ThreadPoolExecutorTest(ThreadPoolMixin, ExecutorTest): +- pass +- +- +-class ProcessPoolExecutorTest(ProcessPoolMixin, ExecutorTest): +- pass +- +- +-class FutureTests(unittest.TestCase): +- def test_done_callback_with_result(self): +- callback_result = [None] +- def fn(callback_future): +- callback_result[0] = callback_future.result() +- +- f = Future() +- f.add_done_callback(fn) +- f.set_result(5) +- self.assertEqual(5, callback_result[0]) +- +- def test_done_callback_with_exception(self): +- callback_exception = [None] +- def fn(callback_future): +- callback_exception[0] = callback_future.exception() +- +- f = Future() +- f.add_done_callback(fn) +- f.set_exception(Exception('test')) +- self.assertEqual(('test',), callback_exception[0].args) +- +- def test_done_callback_with_cancel(self): +- was_cancelled = [None] +- def fn(callback_future): +- was_cancelled[0] = callback_future.cancelled() +- +- f = Future() +- f.add_done_callback(fn) +- self.assertTrue(f.cancel()) +- self.assertTrue(was_cancelled[0]) +- +- def test_done_callback_raises(self): +- with captured_stderr() as stderr: +- raising_was_called = [False] +- fn_was_called = [False] +- +- def raising_fn(callback_future): +- raising_was_called[0] = True +- raise Exception('doh!') +- +- def fn(callback_future): +- fn_was_called[0] = True +- +- f = Future() +- f.add_done_callback(raising_fn) +- f.add_done_callback(fn) +- f.set_result(5) +- self.assertTrue(raising_was_called) +- self.assertTrue(fn_was_called) +- self.assertIn('Exception: doh!', stderr.getvalue()) +- +- def test_done_callback_already_successful(self): +- callback_result = [None] +- def fn(callback_future): +- callback_result[0] = callback_future.result() +- +- f = Future() +- f.set_result(5) +- f.add_done_callback(fn) +- self.assertEqual(5, callback_result[0]) +- +- def test_done_callback_already_failed(self): +- callback_exception = [None] +- def fn(callback_future): +- callback_exception[0] = callback_future.exception() +- +- f = Future() +- f.set_exception(Exception('test')) +- f.add_done_callback(fn) +- self.assertEqual(('test',), callback_exception[0].args) +- +- def test_done_callback_already_cancelled(self): +- was_cancelled = [None] +- def fn(callback_future): +- was_cancelled[0] = callback_future.cancelled() +- +- f = Future() +- self.assertTrue(f.cancel()) +- f.add_done_callback(fn) +- self.assertTrue(was_cancelled[0]) +- +- def test_repr(self): +- self.assertRegexpMatches(repr(PENDING_FUTURE), +- '<Future at 0x[0-9a-f]+ state=pending>') +- self.assertRegexpMatches(repr(RUNNING_FUTURE), +- '<Future at 0x[0-9a-f]+ state=running>') +- self.assertRegexpMatches(repr(CANCELLED_FUTURE), +- '<Future at 0x[0-9a-f]+ state=cancelled>') +- self.assertRegexpMatches(repr(CANCELLED_AND_NOTIFIED_FUTURE), +- '<Future at 0x[0-9a-f]+ state=cancelled>') +- self.assertRegexpMatches( +- repr(EXCEPTION_FUTURE), +- '<Future at 0x[0-9a-f]+ state=finished raised IOError>') +- self.assertRegexpMatches( +- repr(SUCCESSFUL_FUTURE), +- '<Future at 0x[0-9a-f]+ state=finished returned int>') +- +- def test_cancel(self): +- f1 = create_future(state=PENDING) +- f2 = create_future(state=RUNNING) +- f3 = create_future(state=CANCELLED) +- f4 = create_future(state=CANCELLED_AND_NOTIFIED) +- f5 = create_future(state=FINISHED, exception=IOError()) +- f6 = create_future(state=FINISHED, result=5) +- +- self.assertTrue(f1.cancel()) +- self.assertEqual(f1._state, CANCELLED) +- +- self.assertFalse(f2.cancel()) +- self.assertEqual(f2._state, RUNNING) +- +- self.assertTrue(f3.cancel()) +- self.assertEqual(f3._state, CANCELLED) +- +- self.assertTrue(f4.cancel()) +- self.assertEqual(f4._state, CANCELLED_AND_NOTIFIED) +- +- self.assertFalse(f5.cancel()) +- self.assertEqual(f5._state, FINISHED) +- +- self.assertFalse(f6.cancel()) +- self.assertEqual(f6._state, FINISHED) +- +- def test_cancelled(self): +- self.assertFalse(PENDING_FUTURE.cancelled()) +- self.assertFalse(RUNNING_FUTURE.cancelled()) +- self.assertTrue(CANCELLED_FUTURE.cancelled()) +- self.assertTrue(CANCELLED_AND_NOTIFIED_FUTURE.cancelled()) +- self.assertFalse(EXCEPTION_FUTURE.cancelled()) +- self.assertFalse(SUCCESSFUL_FUTURE.cancelled()) +- +- def test_done(self): +- self.assertFalse(PENDING_FUTURE.done()) +- self.assertFalse(RUNNING_FUTURE.done()) +- self.assertTrue(CANCELLED_FUTURE.done()) +- self.assertTrue(CANCELLED_AND_NOTIFIED_FUTURE.done()) +- self.assertTrue(EXCEPTION_FUTURE.done()) +- self.assertTrue(SUCCESSFUL_FUTURE.done()) +- +- def test_running(self): +- self.assertFalse(PENDING_FUTURE.running()) +- self.assertTrue(RUNNING_FUTURE.running()) +- self.assertFalse(CANCELLED_FUTURE.running()) +- self.assertFalse(CANCELLED_AND_NOTIFIED_FUTURE.running()) +- self.assertFalse(EXCEPTION_FUTURE.running()) +- self.assertFalse(SUCCESSFUL_FUTURE.running()) +- +- def test_result_with_timeout(self): +- self.assertRaises(futures.TimeoutError, +- PENDING_FUTURE.result, timeout=0) +- self.assertRaises(futures.TimeoutError, +- RUNNING_FUTURE.result, timeout=0) +- self.assertRaises(futures.CancelledError, +- CANCELLED_FUTURE.result, timeout=0) +- self.assertRaises(futures.CancelledError, +- CANCELLED_AND_NOTIFIED_FUTURE.result, timeout=0) +- self.assertRaises(IOError, EXCEPTION_FUTURE.result, timeout=0) +- self.assertEqual(SUCCESSFUL_FUTURE.result(timeout=0), 42) +- +- def test_result_with_success(self): +- # TODO(brian@sweetapp.com): This test is timing dependant. +- def notification(): +- # Wait until the main thread is waiting for the result. +- time.sleep(1) +- f1.set_result(42) +- +- f1 = create_future(state=PENDING) +- t = threading.Thread(target=notification) +- t.start() +- +- self.assertEqual(f1.result(timeout=5), 42) +- +- def test_result_with_cancel(self): +- # TODO(brian@sweetapp.com): This test is timing dependant. +- def notification(): +- # Wait until the main thread is waiting for the result. +- time.sleep(1) +- f1.cancel() +- +- f1 = create_future(state=PENDING) +- t = threading.Thread(target=notification) +- t.start() +- +- self.assertRaises(futures.CancelledError, f1.result, timeout=5) +- +- def test_exception_with_timeout(self): +- self.assertRaises(futures.TimeoutError, +- PENDING_FUTURE.exception, timeout=0) +- self.assertRaises(futures.TimeoutError, +- RUNNING_FUTURE.exception, timeout=0) +- self.assertRaises(futures.CancelledError, +- CANCELLED_FUTURE.exception, timeout=0) +- self.assertRaises(futures.CancelledError, +- CANCELLED_AND_NOTIFIED_FUTURE.exception, timeout=0) +- self.assertTrue(isinstance(EXCEPTION_FUTURE.exception(timeout=0), +- IOError)) +- self.assertEqual(SUCCESSFUL_FUTURE.exception(timeout=0), None) +- +- def test_exception_with_success(self): +- def notification(): +- # Wait until the main thread is waiting for the exception. +- time.sleep(1) +- with f1._condition: +- f1._state = FINISHED +- f1._exception = IOError() +- f1._condition.notify_all() +- +- f1 = create_future(state=PENDING) +- t = threading.Thread(target=notification) +- t.start() +- +- self.assertTrue(isinstance(f1.exception(timeout=5), IOError)) +- +-@reap_threads +-def test_main(): +- try: +- test_support.run_unittest(ProcessPoolExecutorTest, +- ThreadPoolExecutorTest, +- ProcessPoolWaitTests, +- ThreadPoolWaitTests, +- ProcessPoolAsCompletedTests, +- ThreadPoolAsCompletedTests, +- FutureTests, +- ProcessPoolShutdownTest, +- ThreadPoolShutdownTest) +- finally: +- test_support.reap_children() +- +-if __name__ == "__main__": +- test_main() +diff --git a/third_party/pythonfutures/tox.ini b/third_party/pythonfutures/tox.ini +deleted file mode 100755 +index c1ff2f13f..000000000 +--- a/third_party/pythonfutures/tox.ini ++++ /dev/null +@@ -1,8 +0,0 @@ +-[tox] +-envlist = py26,py27,py31 +- +-[testenv] +-commands={envpython} test_futures.py [] +- +-[testenv:py26] +-deps=unittest2 diff --git a/app-vim/youcompleteme/youcompleteme-20200203.ebuild b/app-vim/youcompleteme/youcompleteme-20200203.ebuild new file mode 100644 index 0000000..5fccb53 --- /dev/null +++ b/app-vim/youcompleteme/youcompleteme-20200203.ebuild @@ -0,0 +1,109 @@ +EAPI="7" +PYTHON_COMPAT=( python3_{4,5,6,7,8} ) +inherit multilib python-single-r1 cmake-utils vim-plugin + +youcompletemev="124661f218e80b96c1f9f3d124e99f9a2fd2d83b" +ycmdv="d3378ca3a3103535c14b104cb916dcbcdaf93eeb" +reqfuv="148451a06781d8196e5fb7e0e2bca7a765368ff1" +ossv="e1902915c6790bcec00b8d551199c8a3537d33c9" +gocodev="5bee97b488366fd20b054d0861b89834ff5bbfb2" + +KEYWORDS="~amd64 ~x86" +SRC_URI=" + https://github.com/Valloric/YouCompleteMe/archive/$youcompletemev.tar.gz -> youcompleteme-$youcompletemev.tar.gz + https://github.com/Valloric/ycmd/archive/$ycmdv.tar.gz -> ycmd-$ycmdv.tar.gz + https://github.com/ross/requests-futures/archive/$reqfuv.tar.gz -> requests-futures-$reqfuv.tar.gz + csharp? ( https://github.com/OmniSharp/omnisharp-server/archive/$ossv.tar.gz -> omnisharp-server-$ossv.tar.gz ) + go? ( https://github.com/nsf/gocode/archive/$gocodev.tar.gz -> gocode-$gocodev.tar.gz ) +" + +DESCRIPTION="vim plugin: a code-completion engine for Vim" +HOMEPAGE="http://valloric.github.io/YouCompleteMe/" + +LICENSE="GPL-3" +IUSE="+clang test go csharp" +REQUIRED_USE="${PYTHON_REQUIRED_USE}" + +COMMON_DEPEND=" + ${PYTHON_DEPS} + clang? ( sys-devel/clang:9 ) + >=dev-libs/boost-1.65:=[python,threads,${PYTHON_USEDEP}] + || ( + app-editors/vim[python,${PYTHON_USEDEP}] + app-editors/gvim[python,${PYTHON_USEDEP}] + ) +" +RDEPEND=" + ${COMMON_DEPEND} + dev-python/bottle[${PYTHON_USEDEP}] + dev-python/future[${PYTHON_USEDEP}] + dev-python/jedi[${PYTHON_USEDEP}] + dev-python/requests[${PYTHON_USEDEP}] + dev-python/sh[${PYTHON_USEDEP}] + dev-python/waitress[${PYTHON_USEDEP}] +" +DEPEND=" + ${COMMON_DEPEND} + test? ( + >=dev-python/mock-1.0.1[${PYTHON_USEDEP}] + >=dev-python/nose-1.3.0[${PYTHON_USEDEP}] + dev-cpp/gmock + dev-cpp/gtest + ) +" + +S="${WORKDIR}/YouCompleteMe-$youcompletemev" +CMAKE_IN_SOURCE_BUILD=1 +CMAKE_USE_DIR=${S}/third_party/ycmd/cpp + +VIM_PLUGIN_HELPFILES="${PN}" + +src_prepare() { + eapply ${FILESDIR}/remove-python2-support.patch + for third_party_module in ycmd requests-futures; do + rm -r "${S}"/third_party/${third_party_module} || die "Failed to remove third party module ${third_party_module}" + done + mv ${WORKDIR}/ycmd-$ycmdv ${S}/third_party/ycmd + use csharp && mv ${WORKDIR}/omnisharp-server-$ossv ${S}/third_party/ycmd/third_party/omnisharp-server + use go && mv ${WORKDIR}/gocode-$gocodev ${S}/third_party/ycmd/third_party/gocode + mv ${WORKDIR}/requests-futures-$reqfuv ${S}/third_party/requests-futures + cmake-utils_src_prepare + default +} + +src_configure() { + local mycmakeargs=( + -DUSE_CLANG_COMPLETER=$(usex clang) + -DUSE_SYSTEM_LIBCLANG=$(usex clang) + -DPATH_TO_LLVM_ROOT=/usr/lib/llvm/9 + -DUSE_SYSTEM_BOOST=ON + ) + cmake-utils_src_configure +} + +src_test() { + cd "${S}/third_party/ycmd/cpp/ycm/tests" + LD_LIBRARY_PATH="${EROOT}"/usr/$(get_libdir)/llvm \ + ./ycm_core_tests || die + + cd "${S}"/python/ycm + + local dirs=( "${S}"/third_party/*/ "${S}"/third_party/ycmd/third_party/*/ ) + local -x PYTHONPATH=${PYTHONPATH}:$(IFS=:; echo "${dirs[*]}") + + nosetests || die +} + +src_install() { + dodoc *.md third_party/ycmd/*.md + rm -r *.md *.sh COPYING.txt third_party/ycmd/cpp || die + rm -r third_party/ycmd/{*.md,*.sh} || die + find python third_party/ycmd -depth -name '*test*' -exec rm -r {} + || die + find python third_party/ycmd -depth -name '*examples*' -exec rm -r {} + || die + rm third_party/ycmd/third_party/clang/lib/libclang.so.* || die + + vim-plugin_src_install + + python_optimize "${ED}" + python_fix_shebang "${ED}" +} |