libv8 6.7.288.46.1 → 7.3.492.27.0beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (408) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -0
  3. data/CHANGELOG.md +4 -0
  4. data/README.md +2 -0
  5. data/ext/libv8/builder.rb +6 -2
  6. data/lib/libv8/version.rb +1 -1
  7. data/vendor/depot_tools/.gitattributes +1 -0
  8. data/vendor/depot_tools/.gitignore +7 -0
  9. data/vendor/depot_tools/CROS_OWNERS +5 -0
  10. data/vendor/depot_tools/OWNERS +12 -1
  11. data/vendor/depot_tools/PRESUBMIT.py +16 -9
  12. data/vendor/depot_tools/README.md +9 -2
  13. data/vendor/depot_tools/autoninja +14 -6
  14. data/vendor/depot_tools/autoninja.bat +11 -1
  15. data/vendor/depot_tools/autoninja.py +40 -18
  16. data/vendor/depot_tools/bb +12 -0
  17. data/vendor/depot_tools/bb.bat +7 -0
  18. data/vendor/depot_tools/bootstrap/win/manifest.txt +1 -1
  19. data/vendor/depot_tools/bootstrap/win/manifest_bleeding_edge.txt +1 -1
  20. data/vendor/depot_tools/bootstrap/win/win_tools.py +2 -1
  21. data/vendor/depot_tools/buildbucket.py +57 -4
  22. data/vendor/depot_tools/cipd +157 -44
  23. data/vendor/depot_tools/cipd.bat +51 -14
  24. data/vendor/depot_tools/cipd.ps1 +104 -42
  25. data/vendor/depot_tools/cipd_client_version +1 -1
  26. data/vendor/depot_tools/cipd_client_version.digests +21 -0
  27. data/vendor/depot_tools/cipd_manifest.txt +19 -6
  28. data/vendor/depot_tools/cipd_manifest.versions +318 -0
  29. data/vendor/depot_tools/clang_format.py +4 -4
  30. data/vendor/depot_tools/cpplint.py +44 -199
  31. data/vendor/depot_tools/dart_format.py +2 -2
  32. data/vendor/depot_tools/detect_host_arch.py +8 -3
  33. data/vendor/depot_tools/download_from_google_storage.py +47 -39
  34. data/vendor/depot_tools/fetch.py +30 -18
  35. data/vendor/depot_tools/fetch_configs/android_internal.py +34 -0
  36. data/vendor/depot_tools/fetch_configs/chromium.py +18 -1
  37. data/vendor/depot_tools/fetch_configs/config_util.py +4 -2
  38. data/vendor/depot_tools/fetch_configs/inspector_protocol.py +40 -0
  39. data/vendor/depot_tools/fetch_configs/node-ci.py +41 -0
  40. data/vendor/depot_tools/fix_encoding.py +3 -3
  41. data/vendor/depot_tools/gclient +1 -1
  42. data/vendor/depot_tools/gclient.py +415 -198
  43. data/vendor/depot_tools/gclient_eval.py +220 -171
  44. data/vendor/depot_tools/gclient_paths.py +142 -0
  45. data/vendor/depot_tools/gclient_scm.py +200 -51
  46. data/vendor/depot_tools/gclient_utils.py +88 -191
  47. data/vendor/depot_tools/gerrit_client.py +13 -0
  48. data/vendor/depot_tools/gerrit_util.py +158 -23
  49. data/vendor/depot_tools/git-nav-upstream +1 -1
  50. data/vendor/depot_tools/git_cache.py +77 -24
  51. data/vendor/depot_tools/git_cl.py +705 -1099
  52. data/vendor/depot_tools/git_common.py +9 -6
  53. data/vendor/depot_tools/git_map_branches.py +19 -2
  54. data/vendor/depot_tools/git_nav_downstream.py +3 -4
  55. data/vendor/depot_tools/git_rebase_update.py +14 -0
  56. data/vendor/depot_tools/git_reparent_branch.py +8 -2
  57. data/vendor/depot_tools/gn.py +38 -3
  58. data/vendor/depot_tools/gsutil.py +8 -3
  59. data/vendor/depot_tools/gsutil.py.bat +15 -0
  60. data/vendor/depot_tools/gsutil.vpython +16 -0
  61. data/vendor/depot_tools/infra/config/OWNERS +0 -1
  62. data/vendor/depot_tools/infra/config/recipes.cfg +3 -2
  63. data/vendor/depot_tools/lucicfg +12 -0
  64. data/vendor/depot_tools/lucicfg.bat +7 -0
  65. data/vendor/depot_tools/man/html/git-map-branches.html +34 -2
  66. data/vendor/depot_tools/man/html/git-new-branch.html +40 -32
  67. data/vendor/depot_tools/man/man1/git-map-branches.1 +24 -5
  68. data/vendor/depot_tools/man/man1/git-new-branch.1 +35 -27
  69. data/vendor/depot_tools/man/src/git-map-branches.demo.1.sh +1 -0
  70. data/vendor/depot_tools/man/src/git-map-branches.txt +10 -0
  71. data/vendor/depot_tools/man/src/git-new-branch.demo.1.sh +9 -4
  72. data/vendor/depot_tools/man/src/git-new-branch.txt +1 -1
  73. data/vendor/depot_tools/metrics.README.md +98 -0
  74. data/vendor/depot_tools/metrics.py +296 -0
  75. data/vendor/depot_tools/metrics_utils.py +303 -0
  76. data/vendor/depot_tools/my_activity.py +91 -29
  77. data/vendor/depot_tools/ninja +1 -1
  78. data/vendor/depot_tools/ninjalog.README.md +64 -0
  79. data/vendor/depot_tools/ninjalog_uploader.py +232 -0
  80. data/vendor/depot_tools/ninjalog_uploader_wrapper.py +116 -0
  81. data/vendor/depot_tools/owners.py +30 -13
  82. data/vendor/depot_tools/owners_finder.py +5 -2
  83. data/vendor/depot_tools/presubmit_canned_checks.py +188 -29
  84. data/vendor/depot_tools/presubmit_support.py +18 -41
  85. data/vendor/depot_tools/pylintrc +23 -19
  86. data/vendor/depot_tools/recipes/OWNERS +2 -0
  87. data/vendor/depot_tools/recipes/README.recipes.md +344 -151
  88. data/vendor/depot_tools/recipes/recipe_modules/bot_update/OWNERS +2 -0
  89. data/vendor/depot_tools/recipes/recipe_modules/bot_update/__init__.py +2 -16
  90. data/vendor/depot_tools/recipes/recipe_modules/bot_update/api.py +141 -99
  91. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/basic.json +5 -8
  92. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/basic_luci.json +5 -8
  93. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/basic_with_branch_heads.json +6 -98
  94. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/clobber.json +4 -9
  95. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/deprecated_got_revision_mapping.json +45 -5
  96. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/gerrit_no_rebase_patch_ref.json +4 -9
  97. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/gerrit_no_reset.json +4 -9
  98. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/{tryjob.json → input_commit_with_id_without_repo.json} +6 -11
  99. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/{tryjob_empty_revision.json → multiple_patch_refs.json} +8 -9
  100. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/no_apply_patch_on_gclient.json +19 -29
  101. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/{trychange.json → refs.json} +4 -9
  102. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/reset_root_solution_revision.json +4 -9
  103. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail.json +51 -6
  104. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail_patch.json +50 -6
  105. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_fail_patch_download.json +51 -6
  106. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_angle.json +17 -25
  107. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_branch_heads.json +17 -25
  108. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_feature_branch.json +18 -26
  109. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_v8_feature_branch.json +18 -26
  110. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_webrtc.json +26 -28
  111. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_v8.json +45 -5
  112. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_v8_head_by_default.json +17 -25
  113. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/unrecognized_commit_repo.json +13 -0
  114. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/with_manifest_name.json +13 -152
  115. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/with_tags.json +4 -9
  116. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.py +185 -202
  117. data/vendor/depot_tools/recipes/recipe_modules/bot_update/resources/bot_update.py +52 -157
  118. data/vendor/depot_tools/recipes/recipe_modules/bot_update/test_api.py +5 -14
  119. data/vendor/depot_tools/recipes/recipe_modules/bot_update/tests/ensure_checkout.py +34 -0
  120. data/vendor/depot_tools/recipes/recipe_modules/cipd/api.py +14 -2
  121. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/basic.json +4 -5
  122. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/basic_pkg.json +4 -5
  123. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/describe-failed.json +7 -5
  124. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/describe-many-instances.json +4 -5
  125. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/mac64.json +4 -5
  126. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/pkg_bad_file.json +9 -3
  127. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/pkg_bad_mode.json +9 -3
  128. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/pkg_bad_verfile.json +9 -3
  129. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/full.expected/win64.json +4 -5
  130. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/junk arch.json +2 -3
  131. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/junk bits.json +2 -3
  132. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_arm_32.json +2 -3
  133. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_arm_64.json +2 -3
  134. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_intel_32.json +2 -3
  135. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_intel_64.json +2 -3
  136. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/linux_mips_64.json +2 -3
  137. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/mac_intel_64.json +2 -3
  138. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/win_intel_32.json +2 -3
  139. data/vendor/depot_tools/recipes/recipe_modules/cipd/examples/platform_suffix.expected/win_intel_64.json +2 -3
  140. data/vendor/depot_tools/recipes/recipe_modules/depot_tools/api.py +13 -8
  141. data/vendor/depot_tools/recipes/recipe_modules/depot_tools/examples/full.expected/basic.json +18 -12
  142. data/vendor/depot_tools/recipes/recipe_modules/depot_tools/examples/full.expected/basic_luci.json +18 -12
  143. data/vendor/depot_tools/recipes/recipe_modules/depot_tools/examples/full.expected/win.json +18 -12
  144. data/vendor/depot_tools/recipes/recipe_modules/depot_tools/examples/full.py +3 -0
  145. data/vendor/depot_tools/recipes/recipe_modules/gclient/__init__.py +1 -0
  146. data/vendor/depot_tools/recipes/recipe_modules/gclient/api.py +58 -46
  147. data/vendor/depot_tools/recipes/recipe_modules/gclient/config.py +65 -22
  148. data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/basic.json +20 -21
  149. data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/buildbot.json +20 -21
  150. data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/revision.json +20 -21
  151. data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.expected/tryserver.json +20 -21
  152. data/vendor/depot_tools/recipes/recipe_modules/gclient/examples/full.py +5 -2
  153. data/vendor/depot_tools/recipes/recipe_modules/gclient/tests/patch_project.py +62 -14
  154. data/vendor/depot_tools/recipes/recipe_modules/gerrit/api.py +24 -38
  155. data/vendor/depot_tools/recipes/recipe_modules/gerrit/examples/full.expected/basic.json +56 -50
  156. data/vendor/depot_tools/recipes/recipe_modules/gerrit/examples/full.py +15 -9
  157. data/vendor/depot_tools/recipes/recipe_modules/git/__init__.py +4 -1
  158. data/vendor/depot_tools/recipes/recipe_modules/git/api.py +34 -22
  159. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic.json +5 -6
  160. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic_branch.json +5 -6
  161. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic_file_name.json +5 -6
  162. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic_hash.json +5 -6
  163. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic_luci.json +222 -0
  164. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic_ref.json +5 -6
  165. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic_submodule_update_force.json +5 -6
  166. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/basic_tags.json +224 -0
  167. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/can_fail_build.json +10 -6
  168. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/cannot_fail_build.json +5 -7
  169. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/cat-file_test.json +5 -6
  170. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/count-objects_delta.json +5 -6
  171. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/count-objects_failed.json +5 -7
  172. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/count-objects_with_bad_output.json +5 -6
  173. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/count-objects_with_bad_output_fails_build.json +10 -5
  174. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/curl_trace_file.json +5 -6
  175. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/git-cache-checkout.json +8 -9
  176. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/platform_win.json +5 -6
  177. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/rebase_failed.json +12 -8
  178. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/remote_not_origin.json +5 -6
  179. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.expected/set_got_revision.json +5 -6
  180. data/vendor/depot_tools/recipes/recipe_modules/git/examples/full.py +27 -11
  181. data/vendor/depot_tools/recipes/recipe_modules/git_cl/api.py +1 -1
  182. data/vendor/depot_tools/recipes/recipe_modules/git_cl/examples/full.expected/basic.json +12 -13
  183. data/vendor/depot_tools/recipes/recipe_modules/gitiles/__init__.py +5 -0
  184. data/vendor/depot_tools/recipes/recipe_modules/gitiles/api.py +120 -5
  185. data/vendor/depot_tools/recipes/recipe_modules/gitiles/examples/full.expected/basic.json +45 -3
  186. data/vendor/depot_tools/recipes/recipe_modules/gitiles/examples/full.py +25 -0
  187. data/vendor/depot_tools/recipes/recipe_modules/gitiles/resources/gerrit_client.py +56 -4
  188. data/vendor/depot_tools/recipes/recipe_modules/gitiles/tests/parse_repo_url.expected/basic.json +6 -0
  189. data/vendor/depot_tools/recipes/recipe_modules/gitiles/tests/parse_repo_url.py +49 -0
  190. data/vendor/depot_tools/recipes/recipe_modules/gsutil/api.py +24 -13
  191. data/vendor/depot_tools/recipes/recipe_modules/gsutil/examples/full.expected/basic.json +13 -14
  192. data/vendor/depot_tools/recipes/recipe_modules/infra_paths/examples/full.expected/basic.json +2 -3
  193. data/vendor/depot_tools/recipes/recipe_modules/infra_paths/examples/full.expected/paths_buildbot_linux.json +2 -3
  194. data/vendor/depot_tools/recipes/recipe_modules/infra_paths/examples/full.expected/paths_buildbot_mac.json +2 -3
  195. data/vendor/depot_tools/recipes/recipe_modules/infra_paths/examples/full.expected/paths_buildbot_win.json +2 -3
  196. data/vendor/depot_tools/recipes/recipe_modules/infra_paths/examples/full.expected/paths_generic_linux.json +2 -3
  197. data/vendor/depot_tools/recipes/recipe_modules/infra_paths/examples/full.expected/paths_generic_mac.json +2 -3
  198. data/vendor/depot_tools/recipes/recipe_modules/infra_paths/examples/full.expected/paths_generic_win.json +2 -3
  199. data/vendor/depot_tools/recipes/recipe_modules/infra_paths/examples/full.expected/paths_kitchen_linux.json +2 -3
  200. data/vendor/depot_tools/recipes/recipe_modules/infra_paths/examples/full.expected/paths_kitchen_mac.json +2 -3
  201. data/vendor/depot_tools/recipes/recipe_modules/infra_paths/examples/full.expected/paths_kitchen_win.json +2 -3
  202. data/vendor/depot_tools/recipes/recipe_modules/infra_paths/path_config.py +1 -2
  203. data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/__init__.py +35 -0
  204. data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/api.py +116 -0
  205. data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/examples/full.expected/linux.json +22 -0
  206. data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/examples/full.expected/mac.json +82 -0
  207. data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/examples/full.expected/win.json +22 -0
  208. data/vendor/depot_tools/recipes/recipe_modules/osx_sdk/examples/full.py +23 -0
  209. data/vendor/depot_tools/recipes/recipe_modules/presubmit/__init__.py +1 -0
  210. data/vendor/depot_tools/recipes/recipe_modules/presubmit/api.py +2 -7
  211. data/vendor/depot_tools/recipes/recipe_modules/presubmit/examples/full.expected/basic.json +7 -6
  212. data/vendor/depot_tools/recipes/recipe_modules/tryserver/__init__.py +1 -0
  213. data/vendor/depot_tools/recipes/recipe_modules/tryserver/api.py +117 -8
  214. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/basic_tags.json +4 -5
  215. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/set_failure_hash_with_no_steps.json +7 -4
  216. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_gerrit_patch.json +98 -7
  217. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_gerrit_patch_and_target_ref.json +147 -0
  218. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_git_patch.json +8 -5
  219. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_git_patch_luci.json +8 -5
  220. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_wrong_patch.json +9 -6
  221. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.expected/with_wrong_patch_new.json +9 -6
  222. data/vendor/depot_tools/recipes/recipe_modules/tryserver/examples/full.py +27 -2
  223. data/vendor/depot_tools/recipes/recipe_modules/tryserver/test_api.py +14 -0
  224. data/vendor/depot_tools/recipes/recipe_modules/windows_sdk/__init__.py +25 -0
  225. data/vendor/depot_tools/recipes/recipe_modules/windows_sdk/api.py +137 -0
  226. data/vendor/depot_tools/recipes/recipe_modules/windows_sdk/examples/full.expected/linux.json +22 -0
  227. data/vendor/depot_tools/recipes/recipe_modules/windows_sdk/examples/full.expected/mac.json +22 -0
  228. data/vendor/depot_tools/recipes/recipe_modules/windows_sdk/examples/full.expected/win.json +107 -0
  229. data/vendor/depot_tools/recipes/recipe_modules/windows_sdk/examples/full.py +26 -0
  230. data/vendor/depot_tools/recipes/recipes.py +37 -27
  231. data/vendor/depot_tools/recipes/recipes/fetch_end_to_end_test.expected/basic.json +7 -10
  232. data/vendor/depot_tools/repo +34 -8
  233. data/vendor/depot_tools/roll_dep.py +52 -49
  234. data/vendor/depot_tools/scm.py +38 -23
  235. data/vendor/depot_tools/setup_color.py +4 -2
  236. data/vendor/depot_tools/split_cl.py +32 -4
  237. data/vendor/depot_tools/subprocess2.py +22 -4
  238. data/vendor/depot_tools/third_party/httplib2/README.chromium +2 -2
  239. data/vendor/depot_tools/third_party/httplib2/__init__.py +242 -158
  240. data/vendor/depot_tools/third_party/httplib2/cacerts.txt +57 -44
  241. data/vendor/depot_tools/third_party/httplib2/socks.py +15 -5
  242. data/vendor/depot_tools/third_party/logilab/README.chromium +2 -4
  243. data/vendor/depot_tools/third_party/logilab/astroid/README.chromium +2 -1
  244. data/vendor/depot_tools/third_party/logilab/astroid/__init__.py +10 -5
  245. data/vendor/depot_tools/third_party/logilab/astroid/__pkginfo__.py +5 -5
  246. data/vendor/depot_tools/third_party/logilab/astroid/arguments.py +233 -0
  247. data/vendor/depot_tools/third_party/logilab/astroid/as_string.py +82 -33
  248. data/vendor/depot_tools/third_party/logilab/astroid/bases.py +137 -153
  249. data/vendor/depot_tools/third_party/logilab/astroid/brain/{builtin_inference.py → brain_builtin_inference.py} +117 -26
  250. data/vendor/depot_tools/third_party/logilab/astroid/brain/brain_dateutil.py +15 -0
  251. data/vendor/depot_tools/third_party/logilab/astroid/brain/{py2gi.py → brain_gi.py} +48 -8
  252. data/vendor/depot_tools/third_party/logilab/astroid/brain/{py2mechanize.py → brain_mechanize.py} +0 -0
  253. data/vendor/depot_tools/third_party/logilab/astroid/brain/{pynose.py → brain_nose.py} +4 -1
  254. data/vendor/depot_tools/third_party/logilab/astroid/brain/brain_numpy.py +62 -0
  255. data/vendor/depot_tools/third_party/logilab/astroid/brain/brain_pytest.py +76 -0
  256. data/vendor/depot_tools/third_party/logilab/astroid/brain/brain_qt.py +44 -0
  257. data/vendor/depot_tools/third_party/logilab/astroid/brain/{pysix_moves.py → brain_six.py} +28 -1
  258. data/vendor/depot_tools/third_party/logilab/astroid/brain/brain_ssl.py +65 -0
  259. data/vendor/depot_tools/third_party/logilab/astroid/brain/brain_stdlib.py +473 -0
  260. data/vendor/depot_tools/third_party/logilab/astroid/builder.py +104 -81
  261. data/vendor/depot_tools/third_party/logilab/astroid/context.py +81 -0
  262. data/vendor/depot_tools/third_party/logilab/astroid/decorators.py +75 -0
  263. data/vendor/depot_tools/third_party/logilab/astroid/exceptions.py +20 -0
  264. data/vendor/depot_tools/third_party/logilab/astroid/inference.py +137 -183
  265. data/vendor/depot_tools/third_party/logilab/astroid/manager.py +45 -169
  266. data/vendor/depot_tools/third_party/logilab/astroid/mixins.py +37 -14
  267. data/vendor/depot_tools/third_party/logilab/astroid/modutils.py +112 -41
  268. data/vendor/depot_tools/third_party/logilab/astroid/node_classes.py +243 -156
  269. data/vendor/depot_tools/third_party/logilab/astroid/nodes.py +35 -22
  270. data/vendor/depot_tools/third_party/logilab/astroid/objects.py +186 -0
  271. data/vendor/depot_tools/third_party/logilab/astroid/protocols.py +157 -102
  272. data/vendor/depot_tools/third_party/logilab/astroid/raw_building.py +32 -8
  273. data/vendor/depot_tools/third_party/logilab/astroid/rebuilder.py +372 -309
  274. data/vendor/depot_tools/third_party/logilab/astroid/scoped_nodes.py +652 -420
  275. data/vendor/depot_tools/third_party/logilab/astroid/test_utils.py +4 -21
  276. data/vendor/depot_tools/third_party/logilab/astroid/transforms.py +96 -0
  277. data/vendor/depot_tools/third_party/logilab/astroid/util.py +89 -0
  278. data/vendor/depot_tools/third_party/logilab/lazy_object_proxy/LICENSE +19 -0
  279. data/vendor/depot_tools/third_party/logilab/lazy_object_proxy/README.chromium +11 -0
  280. data/vendor/depot_tools/third_party/logilab/lazy_object_proxy/__init__.py +20 -0
  281. data/vendor/depot_tools/third_party/logilab/lazy_object_proxy/cext.c +1421 -0
  282. data/vendor/depot_tools/third_party/logilab/lazy_object_proxy/compat.py +9 -0
  283. data/vendor/depot_tools/third_party/logilab/lazy_object_proxy/simple.py +246 -0
  284. data/vendor/depot_tools/third_party/logilab/lazy_object_proxy/slots.py +414 -0
  285. data/vendor/depot_tools/third_party/logilab/lazy_object_proxy/utils.py +13 -0
  286. data/vendor/depot_tools/third_party/logilab/wrapt/LICENSE +24 -0
  287. data/vendor/depot_tools/third_party/logilab/wrapt/README.chromium +11 -0
  288. data/vendor/depot_tools/third_party/logilab/wrapt/__init__.py +19 -0
  289. data/vendor/depot_tools/third_party/logilab/wrapt/_wrappers.c +2729 -0
  290. data/vendor/depot_tools/third_party/logilab/wrapt/arguments.py +96 -0
  291. data/vendor/depot_tools/third_party/logilab/wrapt/decorators.py +512 -0
  292. data/vendor/depot_tools/third_party/logilab/wrapt/importer.py +228 -0
  293. data/vendor/depot_tools/third_party/logilab/wrapt/wrappers.py +901 -0
  294. data/vendor/depot_tools/third_party/pylint/README.chromium +2 -25
  295. data/vendor/depot_tools/third_party/pylint/__pkginfo__.py +13 -3
  296. data/vendor/depot_tools/third_party/pylint/checkers/__init__.py +1 -2
  297. data/vendor/depot_tools/third_party/pylint/checkers/async.py +82 -0
  298. data/vendor/depot_tools/third_party/pylint/checkers/base.py +893 -119
  299. data/vendor/depot_tools/third_party/pylint/checkers/classes.py +342 -204
  300. data/vendor/depot_tools/third_party/pylint/checkers/design_analysis.py +51 -34
  301. data/vendor/depot_tools/third_party/pylint/checkers/exceptions.py +84 -47
  302. data/vendor/depot_tools/third_party/pylint/checkers/format.py +55 -30
  303. data/vendor/depot_tools/third_party/pylint/checkers/imports.py +314 -73
  304. data/vendor/depot_tools/third_party/pylint/checkers/logging.py +10 -8
  305. data/vendor/depot_tools/third_party/pylint/checkers/misc.py +2 -1
  306. data/vendor/depot_tools/third_party/pylint/checkers/newstyle.py +45 -48
  307. data/vendor/depot_tools/third_party/pylint/checkers/python3.py +31 -21
  308. data/vendor/depot_tools/third_party/pylint/checkers/raw_metrics.py +3 -3
  309. data/vendor/depot_tools/third_party/pylint/checkers/similar.py +4 -5
  310. data/vendor/depot_tools/third_party/pylint/checkers/spelling.py +24 -10
  311. data/vendor/depot_tools/third_party/pylint/checkers/stdlib.py +120 -56
  312. data/vendor/depot_tools/third_party/pylint/checkers/strings.py +38 -35
  313. data/vendor/depot_tools/third_party/pylint/checkers/typecheck.py +485 -138
  314. data/vendor/depot_tools/third_party/pylint/checkers/utils.py +319 -142
  315. data/vendor/depot_tools/third_party/pylint/checkers/variables.py +329 -207
  316. data/vendor/depot_tools/third_party/pylint/config.py +739 -76
  317. data/vendor/depot_tools/third_party/pylint/epylint.py +9 -5
  318. data/vendor/depot_tools/third_party/pylint/extensions/__init__.py +0 -0
  319. data/vendor/depot_tools/third_party/pylint/extensions/check_docs.py +311 -0
  320. data/vendor/depot_tools/third_party/pylint/extensions/check_elif.py +62 -0
  321. data/vendor/depot_tools/third_party/{logilab/common → pylint}/graph.py +30 -133
  322. data/vendor/depot_tools/third_party/pylint/gui.py +2 -2
  323. data/vendor/depot_tools/third_party/pylint/interfaces.py +21 -3
  324. data/vendor/depot_tools/third_party/pylint/lint.py +123 -140
  325. data/vendor/depot_tools/third_party/pylint/pyreverse/diadefslib.py +10 -13
  326. data/vendor/depot_tools/third_party/pylint/pyreverse/diagrams.py +15 -4
  327. data/vendor/depot_tools/third_party/pylint/pyreverse/inspector.py +372 -0
  328. data/vendor/depot_tools/third_party/pylint/pyreverse/main.py +30 -7
  329. data/vendor/depot_tools/third_party/pylint/pyreverse/utils.py +80 -2
  330. data/vendor/depot_tools/third_party/{logilab/common → pylint/pyreverse}/vcgutils.py +19 -37
  331. data/vendor/depot_tools/third_party/pylint/pyreverse/writer.py +3 -4
  332. data/vendor/depot_tools/third_party/pylint/reporters/__init__.py +34 -18
  333. data/vendor/depot_tools/third_party/pylint/reporters/guireporter.py +1 -1
  334. data/vendor/depot_tools/third_party/pylint/reporters/html.py +10 -3
  335. data/vendor/depot_tools/third_party/pylint/reporters/json.py +10 -4
  336. data/vendor/depot_tools/third_party/pylint/reporters/text.py +94 -3
  337. data/vendor/depot_tools/third_party/pylint/reporters/ureports/__init__.py +106 -0
  338. data/vendor/depot_tools/third_party/{logilab/common → pylint/reporters}/ureports/html_writer.py +17 -57
  339. data/vendor/depot_tools/third_party/{logilab/common → pylint/reporters}/ureports/nodes.py +52 -74
  340. data/vendor/depot_tools/third_party/{logilab/common → pylint/reporters}/ureports/text_writer.py +14 -60
  341. data/vendor/depot_tools/third_party/pylint/testutils.py +22 -20
  342. data/vendor/depot_tools/third_party/pylint/utils.py +268 -44
  343. data/vendor/depot_tools/third_party/repo/progress.py +42 -0
  344. data/vendor/depot_tools/update_depot_tools +1 -1
  345. data/vendor/depot_tools/upload_metrics.py +25 -0
  346. data/vendor/depot_tools/win_toolchain/get_toolchain_if_necessary.py +45 -15
  347. data/vendor/depot_tools/win_toolchain/package_from_installed.py +71 -24
  348. data/vendor/depot_tools/yapf +1 -1
  349. data/vendor/depot_tools/yapf.bat +1 -1
  350. metadata +92 -77
  351. data/vendor/depot_tools/git-crsync +0 -3
  352. data/vendor/depot_tools/infra/config/cq.cfg +0 -32
  353. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/apply_gerrit_ref.json +0 -29
  354. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/apply_gerrit_ref_custom.json +0 -29
  355. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/buildbot.json +0 -105
  356. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/shallow.json +0 -195
  357. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_angle_deprecated.json +0 -248
  358. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/tryjob_gerrit_v8.json +0 -248
  359. data/vendor/depot_tools/recipes/recipe_modules/bot_update/examples/full.expected/with_manifest_name_no_patch.json +0 -105
  360. data/vendor/depot_tools/recipes/recipe_modules/bot_update/resources/apply_gerrit.py +0 -33
  361. data/vendor/depot_tools/third_party/logilab/astroid/brain/py2pytest.py +0 -31
  362. data/vendor/depot_tools/third_party/logilab/astroid/brain/py2qt4.py +0 -22
  363. data/vendor/depot_tools/third_party/logilab/astroid/brain/py2stdlib.py +0 -334
  364. data/vendor/depot_tools/third_party/logilab/astroid/inspector.py +0 -273
  365. data/vendor/depot_tools/third_party/logilab/astroid/utils.py +0 -239
  366. data/vendor/depot_tools/third_party/logilab/common/LICENSE.txt +0 -339
  367. data/vendor/depot_tools/third_party/logilab/common/README.chromium +0 -11
  368. data/vendor/depot_tools/third_party/logilab/common/__init__.py +0 -175
  369. data/vendor/depot_tools/third_party/logilab/common/__pkginfo__.py +0 -57
  370. data/vendor/depot_tools/third_party/logilab/common/cache.py +0 -114
  371. data/vendor/depot_tools/third_party/logilab/common/changelog.py +0 -238
  372. data/vendor/depot_tools/third_party/logilab/common/clcommands.py +0 -334
  373. data/vendor/depot_tools/third_party/logilab/common/cli.py +0 -211
  374. data/vendor/depot_tools/third_party/logilab/common/compat.py +0 -78
  375. data/vendor/depot_tools/third_party/logilab/common/configuration.py +0 -1105
  376. data/vendor/depot_tools/third_party/logilab/common/contexts.py +0 -5
  377. data/vendor/depot_tools/third_party/logilab/common/corbautils.py +0 -117
  378. data/vendor/depot_tools/third_party/logilab/common/daemon.py +0 -101
  379. data/vendor/depot_tools/third_party/logilab/common/date.py +0 -335
  380. data/vendor/depot_tools/third_party/logilab/common/dbf.py +0 -231
  381. data/vendor/depot_tools/third_party/logilab/common/debugger.py +0 -214
  382. data/vendor/depot_tools/third_party/logilab/common/decorators.py +0 -281
  383. data/vendor/depot_tools/third_party/logilab/common/deprecation.py +0 -189
  384. data/vendor/depot_tools/third_party/logilab/common/fileutils.py +0 -404
  385. data/vendor/depot_tools/third_party/logilab/common/interface.py +0 -71
  386. data/vendor/depot_tools/third_party/logilab/common/logging_ext.py +0 -195
  387. data/vendor/depot_tools/third_party/logilab/common/modutils.py +0 -702
  388. data/vendor/depot_tools/third_party/logilab/common/optik_ext.py +0 -392
  389. data/vendor/depot_tools/third_party/logilab/common/optparser.py +0 -92
  390. data/vendor/depot_tools/third_party/logilab/common/proc.py +0 -277
  391. data/vendor/depot_tools/third_party/logilab/common/pyro_ext.py +0 -180
  392. data/vendor/depot_tools/third_party/logilab/common/pytest.py +0 -1199
  393. data/vendor/depot_tools/third_party/logilab/common/registry.py +0 -1119
  394. data/vendor/depot_tools/third_party/logilab/common/shellutils.py +0 -462
  395. data/vendor/depot_tools/third_party/logilab/common/sphinx_ext.py +0 -87
  396. data/vendor/depot_tools/third_party/logilab/common/sphinxutils.py +0 -122
  397. data/vendor/depot_tools/third_party/logilab/common/table.py +0 -929
  398. data/vendor/depot_tools/third_party/logilab/common/tasksqueue.py +0 -101
  399. data/vendor/depot_tools/third_party/logilab/common/testlib.py +0 -1392
  400. data/vendor/depot_tools/third_party/logilab/common/textutils.py +0 -537
  401. data/vendor/depot_tools/third_party/logilab/common/tree.py +0 -369
  402. data/vendor/depot_tools/third_party/logilab/common/umessage.py +0 -194
  403. data/vendor/depot_tools/third_party/logilab/common/ureports/__init__.py +0 -172
  404. data/vendor/depot_tools/third_party/logilab/common/ureports/docbook_writer.py +0 -140
  405. data/vendor/depot_tools/third_party/logilab/common/urllib2ext.py +0 -89
  406. data/vendor/depot_tools/third_party/logilab/common/visitor.py +0 -109
  407. data/vendor/depot_tools/third_party/logilab/common/xmlrpcutils.py +0 -131
  408. data/vendor/depot_tools/third_party/logilab/common/xmlutils.py +0 -61
@@ -1,5 +1,6 @@
1
1
  URL: https://www.pylint.org/
2
- Version: 1.4.5
2
+ URL: https://pypi.org/project/pylint/#files
3
+ Version: 1.5.6
3
4
  License: GPL
4
5
  License File: LICENSE.txt
5
6
 
@@ -7,7 +8,6 @@ Description:
7
8
  This directory contains the pylint module.
8
9
 
9
10
  Local Modifications:
10
- - applied upstream fix https://bitbucket.org/logilab/pylint/commits/5df347467ee0
11
11
  - applied fix to work around bad interaction between sys.path manipulation in
12
12
  pylint itself and multiprocessing's implementation on Windows (DIFF1)
13
13
 
@@ -28,26 +28,3 @@ index e10ae56..082d8b3 100644
28
28
  else:
29
29
  # Hack that permits running pylint, on Windows, with -m switch
30
30
  # and with --jobs, as in 'python -2 -m pylint .. --jobs'.
31
- @@ -1252,8 +1253,8 @@ group are mutually exclusive.'),
32
-
33
- # insert current working directory to the python path to have a correct
34
- # behaviour
35
- - with fix_import_path(args):
36
- - if self.linter.config.profile:
37
- + if self.linter.config.profile:
38
- + with fix_import_path(args):
39
- print('** profiled run', file=sys.stderr)
40
- import cProfile, pstats
41
- cProfile.runctx('linter.check(%r)' % args, globals(), locals(),
42
- @@ -1262,9 +1263,9 @@ group are mutually exclusive.'),
43
- data.strip_dirs()
44
- data.sort_stats('time', 'calls')
45
- data.print_stats(30)
46
- - else:
47
- - linter.check(args)
48
- - linter.generate_reports()
49
- + else:
50
- + linter.check(args)
51
- + linter.generate_reports()
52
- if exit:
53
- sys.exit(self.linter.msg_status)
@@ -17,12 +17,23 @@
17
17
  """pylint packaging information"""
18
18
  from __future__ import absolute_import
19
19
 
20
+ import sys
21
+ from os.path import join
22
+
23
+
20
24
  modname = distname = 'pylint'
21
25
 
22
- numversion = (1, 4, 5)
26
+ numversion = (1, 5, 6)
23
27
  version = '.'.join([str(num) for num in numversion])
24
28
 
25
- install_requires = ['logilab-common >= 0.53.0', 'astroid >= 1.3.6,<1.4.0', 'six']
29
+ install_requires = [
30
+ 'astroid>=1.4.5,<1.5.0',
31
+ 'six',
32
+ ]
33
+
34
+ if sys.platform == 'win32':
35
+ install_requires.append('colorama')
36
+
26
37
 
27
38
  license = 'GPL'
28
39
  description = "python code static checker"
@@ -62,7 +73,6 @@ long_desc = """\
62
73
  Pylint is shipped with "pylint-gui", "pyreverse" (UML diagram generator)
63
74
  and "symilar" (an independent similarities checker)."""
64
75
 
65
- from os.path import join
66
76
  scripts = [join('bin', filename)
67
77
  for filename in ('pylint', 'pylint-gui', "symilar", "epylint",
68
78
  "pyreverse")]
@@ -44,8 +44,7 @@ import sys
44
44
  import tokenize
45
45
  import warnings
46
46
 
47
- from logilab.common.configuration import OptionsProviderMixIn
48
-
47
+ from pylint.config import OptionsProviderMixIn
49
48
  from pylint.reporters import diff_string
50
49
  from pylint.utils import register_plugins
51
50
  from pylint.interfaces import UNDEFINED
@@ -0,0 +1,82 @@
1
+ # Copyright (c) 2003-2015 LOGILAB S.A. (Paris, FRANCE).
2
+ # http://www.logilab.fr/ -- mailto:contact@logilab.fr
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify it under
5
+ # the terms of the GNU General Public License as published by the Free Software
6
+ # Foundation; either version 2 of the License, or (at your option) any later
7
+ # version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful, but WITHOUT
10
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
+ # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License along with
14
+ # this program; if not, write to the Free Software Foundation, Inc.,
15
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16
+ """Checker for anything related to the async protocol (PEP 492)."""
17
+
18
+ import astroid
19
+ from astroid import exceptions
20
+
21
+ from pylint import checkers
22
+ from pylint.checkers import utils as checker_utils
23
+ from pylint import interfaces
24
+ from pylint import utils
25
+
26
+
27
+ class AsyncChecker(checkers.BaseChecker):
28
+ __implements__ = interfaces.IAstroidChecker
29
+ name = 'async'
30
+ msgs = {
31
+ 'E1700': ('Yield inside async function',
32
+ 'yield-inside-async-function',
33
+ 'Used when an `yield` or `yield from` statement is '
34
+ 'found inside an async function.',
35
+ {'minversion': (3, 5)}),
36
+ 'E1701': ("Async context manager '%s' doesn't implement __aenter__ and __aexit__.",
37
+ 'not-async-context-manager',
38
+ 'Used when an async context manager is used with an object '
39
+ 'that does not implement the async context management protocol.',
40
+ {'minversion': (3, 5)}),
41
+ }
42
+
43
+ def open(self):
44
+ self._ignore_mixin_members = utils.get_global_option(self, 'ignore-mixin-members')
45
+
46
+ @checker_utils.check_messages('yield-inside-async-function')
47
+ def visit_asyncfunctiondef(self, node):
48
+ for child in node.nodes_of_class(astroid.Yield):
49
+ if child.scope() is node:
50
+ self.add_message('yield-inside-async-function', node=child)
51
+
52
+ @checker_utils.check_messages('not-async-context-manager')
53
+ def visit_asyncwith(self, node):
54
+ for ctx_mgr, _ in node.items:
55
+ infered = checker_utils.safe_infer(ctx_mgr)
56
+ if infered is None or infered is astroid.YES:
57
+ continue
58
+
59
+ if isinstance(infered, astroid.Instance):
60
+ try:
61
+ infered.getattr('__aenter__')
62
+ infered.getattr('__aexit__')
63
+ except exceptions.NotFoundError:
64
+ if isinstance(infered, astroid.Instance):
65
+ # If we do not know the bases of this class,
66
+ # just skip it.
67
+ if not checker_utils.has_known_bases(infered):
68
+ continue
69
+ # Just ignore mixin classes.
70
+ if self._ignore_mixin_members:
71
+ if infered.name[-5:].lower() == 'mixin':
72
+ continue
73
+ else:
74
+ continue
75
+
76
+ self.add_message('not-async-context-manager',
77
+ node=node, args=(infered.name, ))
78
+
79
+
80
+ def register(linter):
81
+ """required method to auto register this checker"""
82
+ linter.register_checker(AsyncChecker(linter))
@@ -24,29 +24,31 @@ import re
24
24
  import six
25
25
  from six.moves import zip # pylint: disable=redefined-builtin
26
26
 
27
- from logilab.common.ureports import Table
28
-
29
27
  import astroid
30
28
  import astroid.bases
29
+ import astroid.scoped_nodes
31
30
  from astroid import are_exclusive, InferenceError
32
31
 
33
- from pylint.interfaces import IAstroidChecker, INFERENCE, INFERENCE_FAILURE, HIGH
34
- from pylint.utils import EmptyReport
32
+ from pylint.interfaces import (IAstroidChecker, ITokenChecker, INFERENCE,
33
+ INFERENCE_FAILURE, HIGH)
34
+ from pylint.utils import EmptyReport, deprecated_option
35
35
  from pylint.reporters import diff_string
36
- from pylint.checkers import BaseChecker
36
+ from pylint.checkers import BaseChecker, BaseTokenChecker
37
37
  from pylint.checkers.utils import (
38
38
  check_messages,
39
39
  clobber_in_except,
40
40
  is_builtin_object,
41
41
  is_inside_except,
42
42
  overrides_a_method,
43
- safe_infer,
44
43
  get_argument_from_call,
45
- has_known_bases,
44
+ node_frame_class,
46
45
  NoSuchArgumentError,
47
- is_import_error,
46
+ error_of_type,
48
47
  unimplemented_abstract_methods,
48
+ has_known_bases,
49
+ safe_infer
49
50
  )
51
+ from pylint.reporters.ureports.nodes import Table
50
52
 
51
53
 
52
54
  # regex for class/function/variable/constant name
@@ -56,26 +58,41 @@ CONST_NAME_RGX = re.compile('(([A-Z_][A-Z0-9_]*)|(__.*__))$')
56
58
  COMP_VAR_RGX = re.compile('[A-Za-z_][A-Za-z0-9_]*$')
57
59
  DEFAULT_NAME_RGX = re.compile('[a-z_][a-z0-9_]{2,30}$')
58
60
  CLASS_ATTRIBUTE_RGX = re.compile(r'([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$')
59
- # do not require a doc string on system methods
60
- NO_REQUIRED_DOC_RGX = re.compile('__.*__')
61
- REVERSED_METHODS = (('__getitem__', '__len__'),
62
- ('__reversed__', ))
63
-
61
+ # do not require a doc string on private/system methods
62
+ NO_REQUIRED_DOC_RGX = re.compile('^_')
63
+ REVERSED_PROTOCOL_METHOD = '__reversed__'
64
+ SEQUENCE_PROTOCOL_METHODS = ('__getitem__', '__len__')
65
+ REVERSED_METHODS = (SEQUENCE_PROTOCOL_METHODS,
66
+ (REVERSED_PROTOCOL_METHOD, ))
67
+ TYPECHECK_COMPARISON_OPERATORS = frozenset(('is', 'is not', '==',
68
+ '!=', 'in', 'not in'))
69
+ LITERAL_NODE_TYPES = (astroid.Const, astroid.Dict, astroid.List, astroid.Set)
70
+ UNITTEST_CASE = 'unittest.case'
71
+ BUILTINS = six.moves.builtins.__name__
72
+ TYPE_QNAME = "%s.type" % BUILTINS
64
73
  PY33 = sys.version_info >= (3, 3)
65
74
  PY3K = sys.version_info >= (3, 0)
75
+ PY35 = sys.version_info >= (3, 5)
66
76
  BAD_FUNCTIONS = ['map', 'filter']
67
77
  if sys.version_info < (3, 0):
68
78
  BAD_FUNCTIONS.append('input')
69
79
 
80
+ # Some hints regarding the use of bad builtins.
81
+ BUILTIN_HINTS = {
82
+ 'map': 'Using a list comprehension can be clearer.',
83
+ }
84
+ BUILTIN_HINTS['filter'] = BUILTIN_HINTS['map']
85
+
70
86
  # Name categories that are always consistent with all naming conventions.
71
87
  EXEMPT_NAME_CATEGORIES = set(('exempt', 'ignore'))
72
88
 
73
89
  # A mapping from builtin-qname -> symbol, to be used when generating messages
74
90
  # about dangerous default values as arguments
75
91
  DEFAULT_ARGUMENT_SYMBOLS = dict(
76
- zip(['.'.join([astroid.bases.BUILTINS, x]) for x in ('set', 'dict', 'list')],
92
+ zip(['.'.join([BUILTINS, x]) for x in ('set', 'dict', 'list')],
77
93
  ['set()', '{}', '[]'])
78
94
  )
95
+ REVERSED_COMPS = {'<': '>', '<=': '>=', '>': '<', '>=': '<='}
79
96
 
80
97
  del re
81
98
 
@@ -87,10 +104,10 @@ def _redefines_import(node):
87
104
  current = node
88
105
  while current and not isinstance(current.parent, astroid.ExceptHandler):
89
106
  current = current.parent
90
- if not current or not is_import_error(current.parent):
107
+ if not current or not error_of_type(current.parent, ImportError):
91
108
  return False
92
109
  try_block = current.parent.parent
93
- for import_node in try_block.nodes_of_class((astroid.From, astroid.Import)):
110
+ for import_node in try_block.nodes_of_class((astroid.ImportFrom, astroid.Import)):
94
111
  for name, alias in import_node.names:
95
112
  if alias:
96
113
  if alias == node.name:
@@ -104,7 +121,7 @@ def in_loop(node):
104
121
  parent = node.parent
105
122
  while parent is not None:
106
123
  if isinstance(parent, (astroid.For, astroid.ListComp, astroid.SetComp,
107
- astroid.DictComp, astroid.GenExpr)):
124
+ astroid.DictComp, astroid.GeneratorExp)):
108
125
  return True
109
126
  parent = parent.parent
110
127
  return False
@@ -167,19 +184,25 @@ def _determine_function_name_type(node):
167
184
  # If the function is a property (decorated with @property
168
185
  # or @abc.abstractproperty), the name type is 'attr'.
169
186
  if (isinstance(decorator, astroid.Name) or
170
- (isinstance(decorator, astroid.Getattr) and
187
+ (isinstance(decorator, astroid.Attribute) and
171
188
  decorator.attrname == 'abstractproperty')):
172
189
  infered = safe_infer(decorator)
173
190
  if infered and infered.qname() in PROPERTY_CLASSES:
174
191
  return 'attr'
175
192
  # If the function is decorated using the prop_method.{setter,getter}
176
193
  # form, treat it like an attribute as well.
177
- elif (isinstance(decorator, astroid.Getattr) and
194
+ elif (isinstance(decorator, astroid.Attribute) and
178
195
  decorator.attrname in ('setter', 'deleter')):
179
196
  return 'attr'
180
197
  return 'method'
181
198
 
182
199
 
200
+ def _is_none(node):
201
+ return (node is None or
202
+ (isinstance(node, astroid.Const) and node.value is None) or
203
+ (isinstance(node, astroid.Name) and node.name == 'None')
204
+ )
205
+
183
206
 
184
207
  def _has_abstract_methods(node):
185
208
  """
@@ -242,11 +265,33 @@ def redefined_by_decorator(node):
242
265
  """
243
266
  if node.decorators:
244
267
  for decorator in node.decorators.nodes:
245
- if (isinstance(decorator, astroid.Getattr) and
268
+ if (isinstance(decorator, astroid.Attribute) and
246
269
  getattr(decorator.expr, 'name', None) == node.name):
247
270
  return True
248
271
  return False
249
272
 
273
+
274
+ def _node_type(node):
275
+ """Return the inferred type for `node`
276
+
277
+ If there is more than one possible type, or if inferred type is YES or None,
278
+ return None
279
+ """
280
+ # check there is only one possible type for the assign node. Else we
281
+ # don't handle it for now
282
+ types = set()
283
+ try:
284
+ for var_type in node.infer():
285
+ if var_type == astroid.YES or _is_none(var_type):
286
+ continue
287
+ types.add(var_type)
288
+ if len(types) > 1:
289
+ return
290
+ except InferenceError:
291
+ return
292
+ return types.pop() if types else None
293
+
294
+
250
295
  class _BasicChecker(BaseChecker):
251
296
  __implements__ = IAstroidChecker
252
297
  name = 'basic'
@@ -298,32 +343,89 @@ class BasicErrorChecker(_BasicChecker):
298
343
  'Loops should only have an else clause if they can exit early '
299
344
  'with a break statement, otherwise the statements under else '
300
345
  'should be on the same scope as the loop itself.'),
346
+ 'E0112': ('More than one starred expression in assignment',
347
+ 'too-many-star-expressions',
348
+ 'Emitted when there are more than one starred '
349
+ 'expressions (`*x`) in an assignment. This is a SyntaxError.',
350
+ {'minversion': (3, 0)}),
351
+ 'E0113': ('Starred assignment target must be in a list or tuple',
352
+ 'invalid-star-assignment-target',
353
+ 'Emitted when a star expression is used as a starred '
354
+ 'assignment target.',
355
+ {'minversion': (3, 0)}),
356
+ 'E0114': ('Can use starred expression only in assignment target',
357
+ 'star-needs-assignment-target',
358
+ 'Emitted when a star expression is not used in an '
359
+ 'assignment target.',
360
+ {'minversion': (3, 0)}),
361
+ 'E0115': ('Name %r is nonlocal and global',
362
+ 'nonlocal-and-global',
363
+ 'Emitted when a name is both nonlocal and global.',
364
+ {'minversion': (3, 0)}),
365
+ 'E0116': ("'continue' not supported inside 'finally' clause",
366
+ 'continue-in-finally',
367
+ 'Emitted when the `continue` keyword is found '
368
+ 'inside a finally clause, which is a SyntaxError.'),
369
+ 'E0117': ("nonlocal name %s found without binding",
370
+ 'nonlocal-without-binding',
371
+ 'Emitted when a nonlocal variable does not have an attached '
372
+ 'name somewhere in the parent scopes',
373
+ {'minversion': (3, 0)}),
301
374
  }
302
375
 
303
376
  @check_messages('function-redefined')
304
- def visit_class(self, node):
377
+ def visit_classdef(self, node):
305
378
  self._check_redefinition('class', node)
306
379
 
380
+ @check_messages('too-many-star-expressions',
381
+ 'invalid-star-assignment-target')
382
+ def visit_assign(self, node):
383
+ starred = list(node.targets[0].nodes_of_class(astroid.Starred))
384
+ if len(starred) > 1:
385
+ self.add_message('too-many-star-expressions', node=node)
386
+
387
+ # Check *a = b
388
+ if isinstance(node.targets[0], astroid.Starred):
389
+ self.add_message('invalid-star-assignment-target', node=node)
390
+
391
+ @check_messages('star-needs-assignment-target')
392
+ def visit_starred(self, node):
393
+ """Check that a Starred expression is used in an assignment target."""
394
+ if isinstance(node.parent, astroid.Call):
395
+ # f(*args) is converted to Call(args=[Starred]), so ignore
396
+ # them for this check.
397
+ return
398
+ if PY35 and isinstance(node.parent,
399
+ (astroid.List, astroid.Tuple,
400
+ astroid.Set, astroid.Dict)):
401
+ # PEP 448 unpacking.
402
+ return
403
+
404
+ stmt = node.statement()
405
+ if not isinstance(stmt, astroid.Assign):
406
+ return
407
+
408
+ if stmt.value is node or stmt.value.parent_of(node):
409
+ self.add_message('star-needs-assignment-target', node=node)
410
+
307
411
  @check_messages('init-is-generator', 'return-in-init',
308
412
  'function-redefined', 'return-arg-in-generator',
309
- 'duplicate-argument-name')
310
- def visit_function(self, node):
413
+ 'duplicate-argument-name', 'nonlocal-and-global')
414
+ def visit_functiondef(self, node):
415
+ self._check_nonlocal_and_global(node)
311
416
  if not redefined_by_decorator(node):
312
417
  self._check_redefinition(node.is_method() and 'method' or 'function', node)
313
418
  # checks for max returns, branch, return in __init__
314
419
  returns = node.nodes_of_class(astroid.Return,
315
- skip_klass=(astroid.Function, astroid.Class))
420
+ skip_klass=(astroid.FunctionDef,
421
+ astroid.ClassDef))
316
422
  if node.is_method() and node.name == '__init__':
317
423
  if node.is_generator():
318
424
  self.add_message('init-is-generator', node=node)
319
425
  else:
320
426
  values = [r.value for r in returns]
321
427
  # Are we returning anything but None from constructors
322
- if [v for v in values
323
- if not (v is None or
324
- (isinstance(v, astroid.Const) and v.value is None) or
325
- (isinstance(v, astroid.Name) and v.name == 'None')
326
- )]:
428
+ if [v for v in values if not _is_none(v)]:
327
429
  self.add_message('return-in-init', node=node)
328
430
  elif node.is_generator():
329
431
  # make sure we don't mix non-None returns and yields
@@ -341,18 +443,38 @@ class BasicErrorChecker(_BasicChecker):
341
443
  else:
342
444
  args.add(name)
343
445
 
446
+ visit_asyncfunctiondef = visit_functiondef
447
+
448
+ def _check_nonlocal_and_global(self, node):
449
+ """Check that a name is both nonlocal and global."""
450
+ def same_scope(current):
451
+ return current.scope() is node
452
+
453
+ from_iter = itertools.chain.from_iterable
454
+ nonlocals = set(from_iter(
455
+ child.names for child in node.nodes_of_class(astroid.Nonlocal)
456
+ if same_scope(child)))
457
+ global_vars = set(from_iter(
458
+ child.names for child in node.nodes_of_class(astroid.Global)
459
+ if same_scope(child)))
460
+ for name in nonlocals.intersection(global_vars):
461
+ self.add_message('nonlocal-and-global',
462
+ args=(name, ), node=node)
344
463
 
345
464
  @check_messages('return-outside-function')
346
465
  def visit_return(self, node):
347
- if not isinstance(node.frame(), astroid.Function):
466
+ if not isinstance(node.frame(), astroid.FunctionDef):
348
467
  self.add_message('return-outside-function', node=node)
349
468
 
350
469
  @check_messages('yield-outside-function')
351
470
  def visit_yield(self, node):
352
- if not isinstance(node.frame(), (astroid.Function, astroid.Lambda)):
353
- self.add_message('yield-outside-function', node=node)
471
+ self._check_yield_outside_func(node)
354
472
 
355
- @check_messages('not-in-loop')
473
+ @check_messages('yield-outside-function')
474
+ def visit_yieldfrom(self, node):
475
+ self._check_yield_outside_func(node)
476
+
477
+ @check_messages('not-in-loop', 'continue-in-finally')
356
478
  def visit_continue(self, node):
357
479
  self._check_in_loop(node, 'continue')
358
480
 
@@ -376,8 +498,33 @@ class BasicErrorChecker(_BasicChecker):
376
498
  (node.operand.op == node.op)):
377
499
  self.add_message('nonexistent-operator', node=node, args=node.op*2)
378
500
 
501
+ def _check_nonlocal_without_binding(self, node, name):
502
+ current_scope = node.scope()
503
+ while True:
504
+ if current_scope.parent is None:
505
+ break
506
+
507
+ if not isinstance(current_scope, astroid.FunctionDef):
508
+ self.add_message('nonlocal-without-binding', args=(name, ),
509
+ node=node)
510
+ return
511
+ else:
512
+ if name not in current_scope.locals:
513
+ current_scope = current_scope.parent.scope()
514
+ continue
515
+ else:
516
+ # Okay, found it.
517
+ return
518
+
519
+ self.add_message('nonlocal-without-binding', args=(name, ), node=node)
520
+
521
+ @check_messages('nonlocal-without-binding')
522
+ def visit_nonlocal(self, node):
523
+ for name in node.names:
524
+ self._check_nonlocal_without_binding(node, name)
525
+
379
526
  @check_messages('abstract-class-instantiated')
380
- def visit_callfunc(self, node):
527
+ def visit_call(self, node):
381
528
  """ Check instantiating abstract class with
382
529
  abc.ABCMeta as metaclass.
383
530
  """
@@ -385,8 +532,18 @@ class BasicErrorChecker(_BasicChecker):
385
532
  infered = next(node.func.infer())
386
533
  except astroid.InferenceError:
387
534
  return
388
- if not isinstance(infered, astroid.Class):
535
+
536
+ if not isinstance(infered, astroid.ClassDef):
537
+ return
538
+
539
+ klass = node_frame_class(node)
540
+ if klass is infered:
541
+ # Don't emit the warning if the class is instantiated
542
+ # in its own body or if the call is not an instance
543
+ # creation. If the class is instantiated into its own
544
+ # body, we're expecting that it knows what it is doing.
389
545
  return
546
+
390
547
  # __init__ was called
391
548
  metaclass = infered.metaclass()
392
549
  abstract_methods = _has_abstract_methods(infered)
@@ -405,6 +562,10 @@ class BasicErrorChecker(_BasicChecker):
405
562
  args=(infered.name, ),
406
563
  node=node)
407
564
 
565
+ def _check_yield_outside_func(self, node):
566
+ if not isinstance(node.frame(), (astroid.FunctionDef, astroid.Lambda)):
567
+ self.add_message('yield-outside-function', node=node)
568
+
408
569
  def _check_else_on_loop(self, node):
409
570
  """Check that any loop with an else clause has a break statement."""
410
571
  if node.orelse and not _loop_exits_early(node):
@@ -419,10 +580,19 @@ class BasicErrorChecker(_BasicChecker):
419
580
  _node = node.parent
420
581
  while _node:
421
582
  if isinstance(_node, (astroid.For, astroid.While)):
583
+ if node not in _node.orelse:
584
+ return
585
+
586
+ if isinstance(_node, (astroid.ClassDef, astroid.FunctionDef)):
422
587
  break
588
+ if (isinstance(_node, astroid.TryFinally)
589
+ and node in _node.finalbody
590
+ and isinstance(node, astroid.Continue)):
591
+ self.add_message('continue-in-finally', node=node)
592
+
423
593
  _node = _node.parent
424
- else:
425
- self.add_message('not-in-loop', node=node, args=node_name)
594
+
595
+ self.add_message('not-in-loop', node=node, args=node_name)
426
596
 
427
597
  def _check_redefinition(self, redeftype, node):
428
598
  """check for redefinition of a function / method / class name"""
@@ -491,7 +661,7 @@ functions, methods
491
661
  'usage. Consider using `ast.literal_eval` for safely evaluating '
492
662
  'strings containing Python expressions '
493
663
  'from untrusted sources. '),
494
- 'W0141': ('Used builtin function %r',
664
+ 'W0141': ('Used builtin function %s',
495
665
  'bad-builtin',
496
666
  'Used when a black listed builtin function is used (see the '
497
667
  'bad-function option). Usual black listed functions are the ones '
@@ -508,13 +678,18 @@ functions, methods
508
678
  'A call of assert on a tuple will always evaluate to true if '
509
679
  'the tuple is not empty, and will always evaluate to false if '
510
680
  'it is.'),
511
- 'C0121': ('Missing required attribute "%s"', # W0103
512
- 'missing-module-attribute',
513
- 'Used when an attribute required for modules is missing.'),
514
-
515
- 'E0109': ('Missing argument to reversed()',
516
- 'missing-reversed-argument',
517
- 'Used when reversed() builtin didn\'t receive an argument.'),
681
+ 'W0124': ('Following "as" with another context manager looks like a tuple.',
682
+ 'confusing-with-statement',
683
+ 'Emitted when a `with` statement component returns multiple values '
684
+ 'and uses name binding with `as` only for a part of those values, '
685
+ 'as in with ctx() as a, b. This can be misleading, since it\'s not '
686
+ 'clear if the context manager returns a tuple or if the node without '
687
+ 'a name binding is another context manager.'),
688
+ 'W0125': ('Using a conditional statement with a constant value',
689
+ 'using-constant-test',
690
+ 'Emitted when a conditional statement (If or ternary if) '
691
+ 'uses a constant value for its test. This might not be what '
692
+ 'the user intended to do.'),
518
693
  'E0111': ('The first reversed() argument is not a sequence',
519
694
  'bad-reversed-sequence',
520
695
  'Used when the first argument to reversed() builtin '
@@ -524,11 +699,10 @@ functions, methods
524
699
  }
525
700
 
526
701
  options = (('required-attributes',
527
- {'default' : (), 'type' : 'csv',
528
- 'metavar' : '<attributes>',
529
- 'help' : 'Required attributes for module, separated by a '
530
- 'comma'}
531
- ),
702
+ deprecated_option(opt_type='csv',
703
+ help_msg="Required attributes for module. "
704
+ "This option is obsolete.")),
705
+
532
706
  ('bad-functions',
533
707
  {'default' : BAD_FUNCTIONS,
534
708
  'type' :'csv', 'metavar' : '<builtin function names>',
@@ -550,16 +724,52 @@ functions, methods
550
724
  self.stats = self.linter.add_stats(module=0, function=0,
551
725
  method=0, class_=0)
552
726
 
553
- @check_messages('missing-module-attribute')
554
- def visit_module(self, node):
727
+ @check_messages('using-constant-test')
728
+ def visit_if(self, node):
729
+ self._check_using_constant_test(node, node.test)
730
+
731
+ @check_messages('using-constant-test')
732
+ def visit_ifexp(self, node):
733
+ self._check_using_constant_test(node, node.test)
734
+
735
+ @check_messages('using-constant-test')
736
+ def visit_comprehension(self, node):
737
+ if node.ifs:
738
+ for if_test in node.ifs:
739
+ self._check_using_constant_test(node, if_test)
740
+
741
+ def _check_using_constant_test(self, node, test):
742
+ const_nodes = (
743
+ astroid.Module,
744
+ astroid.scoped_nodes.GeneratorExp,
745
+ astroid.Lambda, astroid.FunctionDef, astroid.ClassDef,
746
+ astroid.bases.Generator, astroid.UnboundMethod,
747
+ astroid.BoundMethod, astroid.Module)
748
+ structs = (astroid.Dict, astroid.Tuple, astroid.Set)
749
+
750
+ # These nodes are excepted, since they are not constant
751
+ # values, requiring a computation to happen. The only type
752
+ # of node in this list which doesn't have this property is
753
+ # Getattr, which is excepted because the conditional statement
754
+ # can be used to verify that the attribute was set inside a class,
755
+ # which is definitely a valid use case.
756
+ except_nodes = (astroid.Attribute, astroid.Call,
757
+ astroid.BinOp, astroid.BoolOp, astroid.UnaryOp,
758
+ astroid.Subscript)
759
+ inferred = None
760
+ emit = isinstance(test, (astroid.Const, ) + structs + const_nodes)
761
+ if not isinstance(test, except_nodes):
762
+ inferred = safe_infer(test)
763
+
764
+ if emit or isinstance(inferred, const_nodes):
765
+ self.add_message('using-constant-test', node=node)
766
+
767
+ def visit_module(self, _):
555
768
  """check module name, docstring and required arguments
556
769
  """
557
770
  self.stats['module'] += 1
558
- for attr in self.config.required_attributes:
559
- if attr not in node:
560
- self.add_message('missing-module-attribute', node=node, args=attr)
561
771
 
562
- def visit_class(self, node): # pylint: disable=unused-argument
772
+ def visit_classdef(self, node): # pylint: disable=unused-argument
563
773
  """check module name, docstring and redefinition
564
774
  increment branch counter
565
775
  """
@@ -567,7 +777,7 @@ functions, methods
567
777
 
568
778
  @check_messages('pointless-statement', 'pointless-string-statement',
569
779
  'expression-not-assigned')
570
- def visit_discard(self, node):
780
+ def visit_expr(self, node):
571
781
  """check for various kind of statements without effect"""
572
782
  expr = node.value
573
783
  if isinstance(expr, astroid.Const) and isinstance(expr.value,
@@ -577,8 +787,8 @@ functions, methods
577
787
  # An attribute docstring is defined as being a string right after
578
788
  # an assignment at the module level, class level or __init__ level.
579
789
  scope = expr.scope()
580
- if isinstance(scope, (astroid.Class, astroid.Module, astroid.Function)):
581
- if isinstance(scope, astroid.Function) and scope.name != '__init__':
790
+ if isinstance(scope, (astroid.ClassDef, astroid.Module, astroid.FunctionDef)):
791
+ if isinstance(scope, astroid.FunctionDef) and scope.name != '__init__':
582
792
  pass
583
793
  else:
584
794
  sibling = expr.previous_sibling()
@@ -593,16 +803,40 @@ functions, methods
593
803
  # * a yield (which are wrapped by a discard node in _ast XXX)
594
804
  # warn W0106 if we have any underlying function call (we can't predict
595
805
  # side effects), else pointless-statement
596
- if (isinstance(expr, (astroid.Yield, astroid.CallFunc)) or
806
+ if (isinstance(expr, (astroid.Yield, astroid.Await, astroid.Call)) or
597
807
  (isinstance(node.parent, astroid.TryExcept) and
598
808
  node.parent.body == [node])):
599
809
  return
600
- if any(expr.nodes_of_class(astroid.CallFunc)):
810
+ if any(expr.nodes_of_class(astroid.Call)):
601
811
  self.add_message('expression-not-assigned', node=node,
602
812
  args=expr.as_string())
603
813
  else:
604
814
  self.add_message('pointless-statement', node=node)
605
815
 
816
+ @staticmethod
817
+ def _filter_vararg(node, call_args):
818
+ # Return the arguments for the given call which are
819
+ # not passed as vararg.
820
+ for arg in call_args:
821
+ if isinstance(arg, astroid.Starred):
822
+ if (isinstance(arg.value, astroid.Name)
823
+ and arg.value.name != node.args.vararg):
824
+ yield arg
825
+ else:
826
+ yield arg
827
+
828
+ @staticmethod
829
+ def _has_variadic_argument(args, variadic_name):
830
+ if not args:
831
+ return True
832
+ for arg in args:
833
+ if isinstance(arg.value, astroid.Name):
834
+ if arg.value.name != variadic_name:
835
+ return True
836
+ else:
837
+ return True
838
+ return False
839
+
606
840
  @check_messages('unnecessary-lambda')
607
841
  def visit_lambda(self, node):
608
842
  """check whether or not the lambda is suspicious
@@ -618,56 +852,53 @@ functions, methods
618
852
  # of the lambda.
619
853
  return
620
854
  call = node.body
621
- if not isinstance(call, astroid.CallFunc):
855
+ if not isinstance(call, astroid.Call):
622
856
  # The body of the lambda must be a function call expression
623
857
  # for the lambda to be unnecessary.
624
858
  return
625
- # XXX are lambda still different with astroid >= 0.18 ?
626
- # *args and **kwargs need to be treated specially, since they
627
- # are structured differently between the lambda and the function
628
- # call (in the lambda they appear in the args.args list and are
629
- # indicated as * and ** by two bits in the lambda's flags, but
630
- # in the function call they are omitted from the args list and
631
- # are indicated by separate attributes on the function call node).
859
+ if (isinstance(node.body.func, astroid.Attribute) and
860
+ isinstance(node.body.func.expr, astroid.Call)):
861
+ # Chained call, the intermediate call might
862
+ # return something else (but we don't check that, yet).
863
+ return
864
+
632
865
  ordinary_args = list(node.args.args)
866
+ new_call_args = list(self._filter_vararg(node, call.args))
633
867
  if node.args.kwarg:
634
- if (not call.kwargs
635
- or not isinstance(call.kwargs, astroid.Name)
636
- or node.args.kwarg != call.kwargs.name):
868
+ if self._has_variadic_argument(call.kwargs, node.args.kwarg):
637
869
  return
638
- elif call.kwargs:
870
+ elif call.kwargs or call.keywords:
639
871
  return
872
+
640
873
  if node.args.vararg:
641
- if (not call.starargs
642
- or not isinstance(call.starargs, astroid.Name)
643
- or node.args.vararg != call.starargs.name):
874
+ if self._has_variadic_argument(call.starargs, node.args.vararg):
644
875
  return
645
876
  elif call.starargs:
646
877
  return
878
+
647
879
  # The "ordinary" arguments must be in a correspondence such that:
648
880
  # ordinary_args[i].name == call.args[i].name.
649
- if len(ordinary_args) != len(call.args):
881
+ if len(ordinary_args) != len(new_call_args):
650
882
  return
651
- for i in range(len(ordinary_args)):
652
- if not isinstance(call.args[i], astroid.Name):
883
+ for arg, passed_arg in zip(ordinary_args, new_call_args):
884
+ if not isinstance(passed_arg, astroid.Name):
653
885
  return
654
- if node.args.args[i].name != call.args[i].name:
886
+ if arg.name != passed_arg.name:
655
887
  return
656
- if (isinstance(node.body.func, astroid.Getattr) and
657
- isinstance(node.body.func.expr, astroid.CallFunc)):
658
- # Chained call, the intermediate call might
659
- # return something else (but we don't check that, yet).
660
- return
661
- self.add_message('unnecessary-lambda', line=node.fromlineno, node=node)
888
+
889
+ self.add_message('unnecessary-lambda', line=node.fromlineno,
890
+ node=node)
662
891
 
663
892
  @check_messages('dangerous-default-value')
664
- def visit_function(self, node):
893
+ def visit_functiondef(self, node):
665
894
  """check function name, docstring, arguments, redefinition,
666
895
  variable names, max locals
667
896
  """
668
897
  self.stats[node.is_method() and 'method' or 'function'] += 1
669
898
  self._check_dangerous_default(node)
670
899
 
900
+ visit_asyncfunctiondef = visit_functiondef
901
+
671
902
  def _check_dangerous_default(self, node):
672
903
  # check for dangerous default values as arguments
673
904
  is_iterable = lambda n: isinstance(n, (astroid.List,
@@ -684,7 +915,7 @@ functions, methods
684
915
 
685
916
  if value is default:
686
917
  msg = DEFAULT_ARGUMENT_SYMBOLS[value.qname()]
687
- elif type(value) is astroid.Instance or is_iterable(value):
918
+ elif isinstance(value, astroid.Instance) or is_iterable(value):
688
919
  # We are here in the following situation(s):
689
920
  # * a dict/set/list/tuple call which wasn't inferred
690
921
  # to a syntax node ({}, () etc.). This can happen
@@ -694,7 +925,7 @@ functions, methods
694
925
  # or a dict.
695
926
  if is_iterable(default):
696
927
  msg = value.pytype()
697
- elif isinstance(default, astroid.CallFunc):
928
+ elif isinstance(default, astroid.Call):
698
929
  msg = '%s() (%s)' % (value.name, value.qname())
699
930
  else:
700
931
  msg = '%s (%s)' % (default.as_string(), value.qname())
@@ -715,7 +946,7 @@ functions, methods
715
946
  """
716
947
  self._check_unreachable(node)
717
948
  # Is it inside final body of a try...finally bloc ?
718
- self._check_not_in_finally(node, 'return', (astroid.Function,))
949
+ self._check_not_in_finally(node, 'return', (astroid.FunctionDef,))
719
950
 
720
951
  @check_messages('unreachable')
721
952
  def visit_continue(self, node):
@@ -749,9 +980,8 @@ functions, methods
749
980
  self.add_message('exec-used', node=node)
750
981
 
751
982
  @check_messages('bad-builtin', 'eval-used',
752
- 'exec-used', 'missing-reversed-argument',
753
- 'bad-reversed-sequence')
754
- def visit_callfunc(self, node):
983
+ 'exec-used', 'bad-reversed-sequence')
984
+ def visit_call(self, node):
755
985
  """visit a CallFunc node -> check if this is not a blacklisted builtin
756
986
  call and check for * or ** use
757
987
  """
@@ -768,7 +998,12 @@ functions, methods
768
998
  elif name == 'eval':
769
999
  self.add_message('eval-used', node=node)
770
1000
  if name in self.config.bad_functions:
771
- self.add_message('bad-builtin', node=node, args=name)
1001
+ hint = BUILTIN_HINTS.get(name)
1002
+ if hint:
1003
+ args = "%r. %s" % (name, hint)
1004
+ else:
1005
+ args = repr(name)
1006
+ self.add_message('bad-builtin', node=node, args=args)
772
1007
 
773
1008
  @check_messages('assert-on-tuple')
774
1009
  def visit_assert(self, node):
@@ -825,14 +1060,14 @@ functions, methods
825
1060
  try:
826
1061
  argument = safe_infer(get_argument_from_call(node, position=0))
827
1062
  except NoSuchArgumentError:
828
- self.add_message('missing-reversed-argument', node=node)
1063
+ pass
829
1064
  else:
830
1065
  if argument is astroid.YES:
831
1066
  return
832
1067
  if argument is None:
833
1068
  # Nothing was infered.
834
1069
  # Try to see if we have iter().
835
- if isinstance(node.args[0], astroid.CallFunc):
1070
+ if isinstance(node.args[0], astroid.Call):
836
1071
  try:
837
1072
  func = next(node.args[0].func.infer())
838
1073
  except InferenceError:
@@ -849,8 +1084,12 @@ functions, methods
849
1084
  return
850
1085
  elif any(ancestor.name == 'dict' and is_builtin_object(ancestor)
851
1086
  for ancestor in argument._proxied.ancestors()):
852
- # mappings aren't accepted by reversed()
853
- self.add_message('bad-reversed-sequence', node=node)
1087
+ # Mappings aren't accepted by reversed(), unless
1088
+ # they provide explicitly a __reversed__ method.
1089
+ try:
1090
+ argument.locals[REVERSED_PROTOCOL_METHOD]
1091
+ except KeyError:
1092
+ self.add_message('bad-reversed-sequence', node=node)
854
1093
  return
855
1094
 
856
1095
  for methods in REVERSED_METHODS:
@@ -862,16 +1101,39 @@ functions, methods
862
1101
  else:
863
1102
  break
864
1103
  else:
865
- # Check if it is a .deque. It doesn't seem that
866
- # we can retrieve special methods
867
- # from C implemented constructs.
868
- if argument._proxied.qname().endswith(".deque"):
869
- return
870
1104
  self.add_message('bad-reversed-sequence', node=node)
871
1105
  elif not isinstance(argument, (astroid.List, astroid.Tuple)):
872
1106
  # everything else is not a proper sequence for reversed()
873
1107
  self.add_message('bad-reversed-sequence', node=node)
874
1108
 
1109
+ @check_messages('confusing-with-statement')
1110
+ def visit_with(self, node):
1111
+ if not PY3K:
1112
+ # in Python 2 a "with" statement with multiple managers coresponds
1113
+ # to multiple nested AST "With" nodes
1114
+ pairs = []
1115
+ parent_node = node.parent
1116
+ if isinstance(parent_node, astroid.With):
1117
+ # we only care about the direct parent, since this method
1118
+ # gets called for each with node anyway
1119
+ pairs.extend(parent_node.items)
1120
+ pairs.extend(node.items)
1121
+ else:
1122
+ # in PY3K a "with" statement with multiple managers coresponds
1123
+ # to one AST "With" node with multiple items
1124
+ pairs = node.items
1125
+ if pairs:
1126
+ for prev_pair, pair in zip(pairs, pairs[1:]):
1127
+ if (isinstance(prev_pair[1], astroid.AssignName) and
1128
+ (pair[1] is None and not isinstance(pair[0], astroid.Call))):
1129
+ # don't emit a message if the second is a function call
1130
+ # there's no way that can be mistaken for a name assignment
1131
+ if PY3K or node.lineno == node.parent.lineno:
1132
+ # if the line number doesn't match
1133
+ # we assume it's a nested "with"
1134
+ self.add_message('confusing-with-statement', node=node)
1135
+
1136
+
875
1137
  _NAME_TYPES = {
876
1138
  'module': (MOD_NAME_RGX, 'module'),
877
1139
  'const': (CONST_NAME_RGX, 'constant'),
@@ -980,14 +1242,14 @@ class NameChecker(_BasicChecker):
980
1242
  self._raise_name_warning(*args)
981
1243
 
982
1244
  @check_messages('blacklisted-name', 'invalid-name')
983
- def visit_class(self, node):
1245
+ def visit_classdef(self, node):
984
1246
  self._check_name('class', node.name, node)
985
1247
  for attr, anodes in six.iteritems(node.instance_attrs):
986
- if not list(node.instance_attr_ancestors(attr)):
1248
+ if not any(node.instance_attr_ancestors(attr)):
987
1249
  self._check_name('attr', attr, anodes[0])
988
1250
 
989
1251
  @check_messages('blacklisted-name', 'invalid-name')
990
- def visit_function(self, node):
1252
+ def visit_functiondef(self, node):
991
1253
  # Do not emit any warnings if the method is just an implementation
992
1254
  # of a base class method.
993
1255
  confidence = HIGH
@@ -1004,21 +1266,23 @@ class NameChecker(_BasicChecker):
1004
1266
  if args is not None:
1005
1267
  self._recursive_check_names(args, node)
1006
1268
 
1269
+ visit_asyncfunctiondef = visit_functiondef
1270
+
1007
1271
  @check_messages('blacklisted-name', 'invalid-name')
1008
1272
  def visit_global(self, node):
1009
1273
  for name in node.names:
1010
1274
  self._check_name('const', name, node)
1011
1275
 
1012
1276
  @check_messages('blacklisted-name', 'invalid-name')
1013
- def visit_assname(self, node):
1277
+ def visit_assignname(self, node):
1014
1278
  """check module level assigned names"""
1015
1279
  frame = node.frame()
1016
- ass_type = node.ass_type()
1280
+ ass_type = node.assign_type()
1017
1281
  if isinstance(ass_type, astroid.Comprehension):
1018
1282
  self._check_name('inlinevar', node.name, node)
1019
1283
  elif isinstance(frame, astroid.Module):
1020
1284
  if isinstance(ass_type, astroid.Assign) and not in_loop(ass_type):
1021
- if isinstance(safe_infer(ass_type.value), astroid.Class):
1285
+ if isinstance(safe_infer(ass_type.value), astroid.ClassDef):
1022
1286
  self._check_name('class', node.name, node)
1023
1287
  else:
1024
1288
  if not _redefines_import(node):
@@ -1027,19 +1291,19 @@ class NameChecker(_BasicChecker):
1027
1291
  self._check_name('const', node.name, node)
1028
1292
  elif isinstance(ass_type, astroid.ExceptHandler):
1029
1293
  self._check_name('variable', node.name, node)
1030
- elif isinstance(frame, astroid.Function):
1294
+ elif isinstance(frame, astroid.FunctionDef):
1031
1295
  # global introduced variable aren't in the function locals
1032
1296
  if node.name in frame and node.name not in frame.argnames():
1033
1297
  if not _redefines_import(node):
1034
1298
  self._check_name('variable', node.name, node)
1035
- elif isinstance(frame, astroid.Class):
1299
+ elif isinstance(frame, astroid.ClassDef):
1036
1300
  if not list(frame.local_attr_ancestors(node.name)):
1037
1301
  self._check_name('class_attribute', node.name, node)
1038
1302
 
1039
1303
  def _recursive_check_names(self, args, node):
1040
1304
  """check names in a possibly recursive list <arg>"""
1041
1305
  for arg in args:
1042
- if isinstance(arg, astroid.AssName):
1306
+ if isinstance(arg, astroid.AssignName):
1043
1307
  self._check_name('argument', arg.name, node)
1044
1308
  else:
1045
1309
  self._recursive_check_names(arg.elts, node)
@@ -1119,22 +1383,34 @@ class DocStringChecker(_BasicChecker):
1119
1383
  self._check_docstring('module', node)
1120
1384
 
1121
1385
  @check_messages('missing-docstring', 'empty-docstring')
1122
- def visit_class(self, node):
1386
+ def visit_classdef(self, node):
1123
1387
  if self.config.no_docstring_rgx.match(node.name) is None:
1124
1388
  self._check_docstring('class', node)
1125
1389
 
1390
+ @staticmethod
1391
+ def _is_setter_or_deleter(node):
1392
+ names = {'setter', 'deleter'}
1393
+ for decorator in node.decorators.nodes:
1394
+ if (isinstance(decorator, astroid.Attribute)
1395
+ and decorator.attrname in names):
1396
+ return True
1397
+ return False
1398
+
1126
1399
  @check_messages('missing-docstring', 'empty-docstring')
1127
- def visit_function(self, node):
1400
+ def visit_functiondef(self, node):
1128
1401
  if self.config.no_docstring_rgx.match(node.name) is None:
1129
1402
  ftype = node.is_method() and 'method' or 'function'
1130
- if isinstance(node.parent.frame(), astroid.Class):
1403
+ if node.decorators and self._is_setter_or_deleter(node):
1404
+ return
1405
+
1406
+ if isinstance(node.parent.frame(), astroid.ClassDef):
1131
1407
  overridden = False
1132
1408
  confidence = (INFERENCE if has_known_bases(node.parent.frame())
1133
1409
  else INFERENCE_FAILURE)
1134
1410
  # check if node is from a method overridden by its ancestor
1135
1411
  for ancestor in node.parent.frame().ancestors():
1136
1412
  if node.name in ancestor and \
1137
- isinstance(ancestor[node.name], astroid.Function):
1413
+ isinstance(ancestor[node.name], astroid.FunctionDef):
1138
1414
  overridden = True
1139
1415
  break
1140
1416
  self._check_docstring(ftype, node,
@@ -1143,6 +1419,8 @@ class DocStringChecker(_BasicChecker):
1143
1419
  else:
1144
1420
  self._check_docstring(ftype, node)
1145
1421
 
1422
+ visit_asyncfunctiondef = visit_functiondef
1423
+
1146
1424
  def _check_docstring(self, node_type, node, report_missing=True,
1147
1425
  confidence=HIGH):
1148
1426
  """check the node has a non empty docstring"""
@@ -1164,8 +1442,8 @@ class DocStringChecker(_BasicChecker):
1164
1442
  if node_type != 'module' and max_lines > -1 and lines < max_lines:
1165
1443
  return
1166
1444
  self.stats['undocumented_'+node_type] += 1
1167
- if (node.body and isinstance(node.body[0], astroid.Discard) and
1168
- isinstance(node.body[0].value, astroid.CallFunc)):
1445
+ if (node.body and isinstance(node.body[0], astroid.Expr) and
1446
+ isinstance(node.body[0].value, astroid.Call)):
1169
1447
  # Most likely a string with a format call. Let's see.
1170
1448
  func = safe_infer(node.body[0].value.func)
1171
1449
  if (isinstance(func, astroid.BoundMethod)
@@ -1212,7 +1490,7 @@ class LambdaForComprehensionChecker(_BasicChecker):
1212
1490
  }
1213
1491
 
1214
1492
  @check_messages('deprecated-lambda')
1215
- def visit_callfunc(self, node):
1493
+ def visit_call(self, node):
1216
1494
  """visit a CallFunc node, check if map or filter are called with a
1217
1495
  lambda
1218
1496
  """
@@ -1226,6 +1504,497 @@ class LambdaForComprehensionChecker(_BasicChecker):
1226
1504
  self.add_message('deprecated-lambda', node=node)
1227
1505
 
1228
1506
 
1507
+ class RecommandationChecker(_BasicChecker):
1508
+ msgs = {'C0200': ('Consider using enumerate instead of iterating with range and len',
1509
+ 'consider-using-enumerate',
1510
+ 'Emitted when code that iterates with range and len is '
1511
+ 'encountered. Such code can be simplified by using the '
1512
+ 'enumerate builtin.'),
1513
+ }
1514
+
1515
+ @staticmethod
1516
+ def _is_builtin(node, function):
1517
+ inferred = safe_infer(node)
1518
+ if not inferred:
1519
+ return False
1520
+ return is_builtin_object(inferred) and inferred.name == function
1521
+
1522
+ @check_messages('consider-using-enumerate')
1523
+ def visit_for(self, node):
1524
+ """Emit a convention whenever range and len are used for indexing."""
1525
+ # Verify that we have a `range(len(...))` call and that the object
1526
+ # which is iterated is used as a subscript in the body of the for.
1527
+
1528
+ # Is it a proper range call?
1529
+ if not isinstance(node.iter, astroid.Call):
1530
+ return
1531
+ if not self._is_builtin(node.iter.func, 'range'):
1532
+ return
1533
+ if len(node.iter.args) != 1:
1534
+ return
1535
+
1536
+ # Is it a proper len call?
1537
+ if not isinstance(node.iter.args[0], astroid.Call):
1538
+ return
1539
+ second_func = node.iter.args[0].func
1540
+ if not self._is_builtin(second_func, 'len'):
1541
+ return
1542
+ len_args = node.iter.args[0].args
1543
+ if not len_args or len(len_args) != 1:
1544
+ return
1545
+ iterating_object = len_args[0]
1546
+ if not isinstance(iterating_object, astroid.Name):
1547
+ return
1548
+
1549
+ # Verify that the body of the for loop uses a subscript
1550
+ # with the object that was iterated. This uses some heuristics
1551
+ # in order to make sure that the same object is used in the
1552
+ # for body.
1553
+ for child in node.body:
1554
+ for subscript in child.nodes_of_class(astroid.Subscript):
1555
+ if not isinstance(subscript.value, astroid.Name):
1556
+ continue
1557
+ if not isinstance(subscript.slice, astroid.Index):
1558
+ continue
1559
+ if not isinstance(subscript.slice.value, astroid.Name):
1560
+ continue
1561
+ if subscript.slice.value.name != node.target.name:
1562
+ continue
1563
+ if iterating_object.name != subscript.value.name:
1564
+ continue
1565
+ if subscript.value.scope() != node.scope():
1566
+ # Ignore this subscript if it's not in the same
1567
+ # scope. This means that in the body of the for
1568
+ # loop, another scope was created, where the same
1569
+ # name for the iterating object was used.
1570
+ continue
1571
+ self.add_message('consider-using-enumerate', node=node)
1572
+ return
1573
+
1574
+
1575
+ def _is_one_arg_pos_call(call):
1576
+ """Is this a call with exactly 1 argument,
1577
+ where that argument is positional?
1578
+ """
1579
+ return (isinstance(call, astroid.Call)
1580
+ and len(call.args) == 1 and not call.keywords)
1581
+
1582
+
1583
+ class ComparisonChecker(_BasicChecker):
1584
+ """Checks for comparisons
1585
+
1586
+ - singleton comparison: 'expr == True', 'expr == False' and 'expr == None'
1587
+ - yoda condition: 'const "comp" right' where comp can be '==', '!=', '<',
1588
+ '<=', '>' or '>=', and right can be a variable, an attribute, a method or
1589
+ a function
1590
+ """
1591
+ msgs = {'C0121': ('Comparison to %s should be %s',
1592
+ 'singleton-comparison',
1593
+ 'Used when an expression is compared to singleton '
1594
+ 'values like True, False or None.'),
1595
+ 'C0122': ('Comparison should be %s',
1596
+ 'misplaced-comparison-constant',
1597
+ 'Used when the constant is placed on the left side'
1598
+ 'of a comparison. It is usually clearer in intent to '
1599
+ 'place it in the right hand side of the comparison.'),
1600
+ 'C0123': ('Using type() instead of isinstance() for a typecheck.',
1601
+ 'unidiomatic-typecheck',
1602
+ 'The idiomatic way to perform an explicit typecheck in '
1603
+ 'Python is to use isinstance(x, Y) rather than '
1604
+ 'type(x) == Y, type(x) is Y. Though there are unusual '
1605
+ 'situations where these give different results.',
1606
+ {'old_names': [('W0154', 'unidiomatic-typecheck')]}),
1607
+ }
1608
+
1609
+ def _check_singleton_comparison(self, singleton, root_node):
1610
+ if singleton.value is True:
1611
+ suggestion = "just 'expr' or 'expr is True'"
1612
+ self.add_message('singleton-comparison',
1613
+ node=root_node,
1614
+ args=(True, suggestion))
1615
+ elif singleton.value is False:
1616
+ suggestion = "'not expr' or 'expr is False'"
1617
+ self.add_message('singleton-comparison',
1618
+ node=root_node,
1619
+ args=(False, suggestion))
1620
+ elif singleton.value is None:
1621
+ self.add_message('singleton-comparison',
1622
+ node=root_node,
1623
+ args=(None, "'expr is None'"))
1624
+
1625
+ def _check_misplaced_constant(self, node, left, right, operator):
1626
+ if isinstance(right, astroid.Const):
1627
+ return
1628
+ operator = REVERSED_COMPS.get(operator, operator)
1629
+ suggestion = '%s %s %r' % (right.as_string(), operator, left.value)
1630
+ self.add_message('misplaced-comparison-constant', node=node,
1631
+ args=(suggestion,))
1632
+
1633
+ @check_messages('singleton-comparison', 'misplaced-comparison-constant',
1634
+ 'unidiomatic-typecheck')
1635
+ def visit_compare(self, node):
1636
+ self._check_unidiomatic_typecheck(node)
1637
+ # NOTE: this checker only works with binary comparisons like 'x == 42'
1638
+ # but not 'x == y == 42'
1639
+ if len(node.ops) != 1:
1640
+ return
1641
+ left = node.left
1642
+ operator, right = node.ops[0]
1643
+ if (operator in ('<', '<=', '>', '>=', '!=', '==')
1644
+ and isinstance(left, astroid.Const)):
1645
+ self._check_misplaced_constant(node, left, right, operator)
1646
+
1647
+ if operator == '==':
1648
+ if isinstance(left, astroid.Const):
1649
+ self._check_singleton_comparison(left, node)
1650
+ elif isinstance(right, astroid.Const):
1651
+ self._check_singleton_comparison(right, node)
1652
+
1653
+ def _check_unidiomatic_typecheck(self, node):
1654
+ operator, right = node.ops[0]
1655
+ if operator in TYPECHECK_COMPARISON_OPERATORS:
1656
+ left = node.left
1657
+ if _is_one_arg_pos_call(left):
1658
+ self._check_type_x_is_y(node, left, operator, right)
1659
+
1660
+ def _check_type_x_is_y(self, node, left, operator, right):
1661
+ """Check for expressions like type(x) == Y."""
1662
+ left_func = safe_infer(left.func)
1663
+ if not (isinstance(left_func, astroid.ClassDef)
1664
+ and left_func.qname() == TYPE_QNAME):
1665
+ return
1666
+
1667
+ if operator in ('is', 'is not') and _is_one_arg_pos_call(right):
1668
+ right_func = safe_infer(right.func)
1669
+ if (isinstance(right_func, astroid.ClassDef)
1670
+ and right_func.qname() == TYPE_QNAME):
1671
+ # type(x) == type(a)
1672
+ right_arg = safe_infer(right.args[0])
1673
+ if not isinstance(right_arg, LITERAL_NODE_TYPES):
1674
+ # not e.g. type(x) == type([])
1675
+ return
1676
+ self.add_message('unidiomatic-typecheck', node=node)
1677
+
1678
+
1679
+ class ElifChecker(BaseTokenChecker):
1680
+ """Checks needing to distinguish "else if" from "elif"
1681
+
1682
+ This checker mixes the astroid and the token approaches in order to create
1683
+ knowledge about whether a "else if" node is a true "else if" node, or a
1684
+ "elif" node.
1685
+
1686
+ The following checks depend on this implementation:
1687
+ - check for too many nested blocks (if/elif structures aren't considered
1688
+ as nested)
1689
+ - to be continued
1690
+ """
1691
+ __implements__ = (ITokenChecker, IAstroidChecker)
1692
+ name = 'elif'
1693
+ msgs = {'R0101': ('Too many nested blocks (%s/%s)',
1694
+ 'too-many-nested-blocks',
1695
+ 'Used when a function or a method has too many nested '
1696
+ 'blocks. This makes the code less understandable and '
1697
+ 'maintainable.'),
1698
+ 'R0102': ('The if statement can be replaced with %s',
1699
+ 'simplifiable-if-statement',
1700
+ 'Used when an if statement can be replaced with '
1701
+ '\'bool(test)\'. '),
1702
+ }
1703
+ options = (('max-nested-blocks',
1704
+ {'default' : 5, 'type' : 'int', 'metavar' : '<int>',
1705
+ 'help': 'Maximum number of nested blocks for function / '
1706
+ 'method body'}
1707
+ ),)
1708
+
1709
+ def __init__(self, linter=None):
1710
+ BaseTokenChecker.__init__(self, linter)
1711
+ self._init()
1712
+
1713
+ def _init(self):
1714
+ self._nested_blocks = []
1715
+ self._elifs = []
1716
+ self._if_counter = 0
1717
+ self._nested_blocks_msg = None
1718
+
1719
+ @staticmethod
1720
+ def _is_bool_const(node):
1721
+ return (isinstance(node.value, astroid.Const)
1722
+ and isinstance(node.value.value, bool))
1723
+
1724
+ def _is_actual_elif(self, node):
1725
+ """Check if the given node is an actual elif
1726
+
1727
+ This is a problem we're having with the builtin ast module,
1728
+ which splits `elif` branches into a separate if statement.
1729
+ Unfortunately we need to know the exact type in certain
1730
+ cases.
1731
+ """
1732
+
1733
+ if isinstance(node.parent, astroid.If):
1734
+ orelse = node.parent.orelse
1735
+ # current if node must directly follow a "else"
1736
+ if orelse and orelse == [node]:
1737
+ if self._elifs[self._if_counter]:
1738
+ return True
1739
+ return False
1740
+
1741
+ def _check_simplifiable_if(self, node):
1742
+ """Check if the given if node can be simplified.
1743
+
1744
+ The if statement can be reduced to a boolean expression
1745
+ in some cases. For instance, if there are two branches
1746
+ and both of them return a boolean value that depends on
1747
+ the result of the statement's test, then this can be reduced
1748
+ to `bool(test)` without losing any functionality.
1749
+ """
1750
+
1751
+ if self._is_actual_elif(node):
1752
+ # Not interested in if statements with multiple branches.
1753
+ return
1754
+ if len(node.orelse) != 1 or len(node.body) != 1:
1755
+ return
1756
+
1757
+ # Check if both branches can be reduced.
1758
+ first_branch = node.body[0]
1759
+ else_branch = node.orelse[0]
1760
+ if isinstance(first_branch, astroid.Return):
1761
+ if not isinstance(else_branch, astroid.Return):
1762
+ return
1763
+ first_branch_is_bool = self._is_bool_const(first_branch)
1764
+ else_branch_is_bool = self._is_bool_const(else_branch)
1765
+ reduced_to = "'return bool(test)'"
1766
+ elif isinstance(first_branch, astroid.Assign):
1767
+ if not isinstance(else_branch, astroid.Assign):
1768
+ return
1769
+ first_branch_is_bool = self._is_bool_const(first_branch)
1770
+ else_branch_is_bool = self._is_bool_const(else_branch)
1771
+ reduced_to = "'var = bool(test)'"
1772
+ else:
1773
+ return
1774
+
1775
+ if not first_branch_is_bool or not else_branch_is_bool:
1776
+ return
1777
+ if not first_branch.value.value:
1778
+ # This is a case that can't be easily simplified and
1779
+ # if it can be simplified, it will usually result in a
1780
+ # code that's harder to understand and comprehend.
1781
+ # Let's take for instance `arg and arg <= 3`. This could theoretically be
1782
+ # reduced to `not arg or arg > 3`, but the net result is that now the
1783
+ # condition is harder to understand, because it requires understanding of
1784
+ # an extra clause:
1785
+ # * first, there is the negation of truthness with `not arg`
1786
+ # * the second clause is `arg > 3`, which occurs when arg has a
1787
+ # a truth value, but it implies that `arg > 3` is equivalent
1788
+ # with `arg and arg > 3`, which means that the user must
1789
+ # think about this assumption when evaluating `arg > 3`.
1790
+ # The original form is easier to grasp.
1791
+ return
1792
+
1793
+ self.add_message('simplifiable-if-statement', node=node,
1794
+ args=(reduced_to, ))
1795
+
1796
+ def process_tokens(self, tokens):
1797
+ # Process tokens and look for 'if' or 'elif'
1798
+ for _, token, _, _, _ in tokens:
1799
+ if token == 'elif':
1800
+ self._elifs.append(True)
1801
+ elif token == 'if':
1802
+ self._elifs.append(False)
1803
+
1804
+ def leave_module(self, _):
1805
+ self._init()
1806
+
1807
+ @check_messages('too-many-nested-blocks')
1808
+ def visit_tryexcept(self, node):
1809
+ self._check_nested_blocks(node)
1810
+
1811
+ visit_tryfinally = visit_tryexcept
1812
+ visit_while = visit_tryexcept
1813
+ visit_for = visit_while
1814
+
1815
+ def visit_ifexp(self, _):
1816
+ self._if_counter += 1
1817
+
1818
+ def visit_comprehension(self, node):
1819
+ self._if_counter += len(node.ifs)
1820
+
1821
+ @check_messages('too-many-nested-blocks', 'simplifiable-if-statement')
1822
+ def visit_if(self, node):
1823
+ self._check_simplifiable_if(node)
1824
+ self._check_nested_blocks(node)
1825
+ self._if_counter += 1
1826
+
1827
+ @check_messages('too-many-nested-blocks')
1828
+ def leave_functiondef(self, _):
1829
+ # new scope = reinitialize the stack of nested blocks
1830
+ self._nested_blocks = []
1831
+ # if there is a waiting message left, send it
1832
+ if self._nested_blocks_msg:
1833
+ self.add_message('too-many-nested-blocks',
1834
+ node=self._nested_blocks_msg[0],
1835
+ args=self._nested_blocks_msg[1])
1836
+ self._nested_blocks_msg = None
1837
+
1838
+ def _check_nested_blocks(self, node):
1839
+ """Update and check the number of nested blocks
1840
+ """
1841
+ # only check block levels inside functions or methods
1842
+ if not isinstance(node.scope(), astroid.FunctionDef):
1843
+ return
1844
+ # messages are triggered on leaving the nested block. Here we save the
1845
+ # stack in case the current node isn't nested in the previous one
1846
+ nested_blocks = self._nested_blocks[:]
1847
+ if node.parent == node.scope():
1848
+ self._nested_blocks = [node]
1849
+ else:
1850
+ # go through ancestors from the most nested to the less
1851
+ for ancestor_node in reversed(self._nested_blocks):
1852
+ if ancestor_node == node.parent:
1853
+ break
1854
+ self._nested_blocks.pop()
1855
+ # if the node is a elif, this should not be another nesting level
1856
+ if isinstance(node, astroid.If) and self._elifs[self._if_counter]:
1857
+ if self._nested_blocks:
1858
+ self._nested_blocks.pop()
1859
+ self._nested_blocks.append(node)
1860
+ # send message only once per group of nested blocks
1861
+ if len(nested_blocks) > self.config.max_nested_blocks:
1862
+ if len(nested_blocks) > len(self._nested_blocks):
1863
+ self.add_message('too-many-nested-blocks', node=nested_blocks[0],
1864
+ args=(len(nested_blocks),
1865
+ self.config.max_nested_blocks))
1866
+ self._nested_blocks_msg = None
1867
+ else:
1868
+ # if time has not come yet to send the message (ie the stack of
1869
+ # nested nodes is still increasing), save it in case the
1870
+ # current node is the last one of the function
1871
+ self._nested_blocks_msg = (self._nested_blocks[0],
1872
+ (len(self._nested_blocks),
1873
+ self.config.max_nested_blocks))
1874
+
1875
+ class NotChecker(_BasicChecker):
1876
+ """checks for too many not in comparison expressions
1877
+
1878
+ - "not not" should trigger a warning
1879
+ - "not" followed by a comparison should trigger a warning
1880
+ """
1881
+ msgs = {'C0113': ('Consider changing "%s" to "%s"',
1882
+ 'unneeded-not',
1883
+ 'Used when a boolean expression contains an unneeded '
1884
+ 'negation.'),
1885
+ }
1886
+
1887
+ reverse_op = {'<': '>=', '<=': '>', '>': '<=', '>=': '<', '==': '!=',
1888
+ '!=': '==', 'in': 'not in', 'is': 'is not'}
1889
+ # sets are not ordered, so for example "not set(LEFT_VALS) <= set(RIGHT_VALS)" is
1890
+ # not equivalent to "set(LEFT_VALS) > set(RIGHT_VALS)"
1891
+ skipped_nodes = (astroid.Set, )
1892
+ # 'builtins' py3, '__builtin__' py2
1893
+ skipped_classnames = ['%s.%s' % (six.moves.builtins.__name__, qname)
1894
+ for qname in ('set', 'frozenset')]
1895
+
1896
+ @check_messages('unneeded-not')
1897
+ def visit_unaryop(self, node):
1898
+ if node.op != 'not':
1899
+ return
1900
+ operand = node.operand
1901
+
1902
+ if isinstance(operand, astroid.UnaryOp) and operand.op == 'not':
1903
+ self.add_message('unneeded-not', node=node,
1904
+ args=(node.as_string(),
1905
+ operand.operand.as_string()))
1906
+ elif isinstance(operand, astroid.Compare):
1907
+ left = operand.left
1908
+ # ignore multiple comparisons
1909
+ if len(operand.ops) > 1:
1910
+ return
1911
+ operator, right = operand.ops[0]
1912
+ if operator not in self.reverse_op:
1913
+ return
1914
+ # Ignore __ne__ as function of __eq__
1915
+ frame = node.frame()
1916
+ if frame.name == '__ne__' and operator == '==':
1917
+ return
1918
+ for _type in (_node_type(left), _node_type(right)):
1919
+ if not _type:
1920
+ return
1921
+ if isinstance(_type, self.skipped_nodes):
1922
+ return
1923
+ if (isinstance(_type, astroid.Instance) and
1924
+ _type.qname() in self.skipped_classnames):
1925
+ return
1926
+ suggestion = '%s %s %s' % (left.as_string(),
1927
+ self.reverse_op[operator],
1928
+ right.as_string())
1929
+ self.add_message('unneeded-not', node=node,
1930
+ args=(node.as_string(), suggestion))
1931
+
1932
+
1933
+ class MultipleTypesChecker(BaseChecker):
1934
+ """Checks for variable type redefinitions (NoneType excepted)
1935
+
1936
+ At a function, method, class or module scope
1937
+
1938
+ This rule could be improved:
1939
+ - Currently, if an attribute is set to different types in 2 methods of a
1940
+ same class, it won't be detected (see functional test)
1941
+ - One could improve the support for inference on assignment with tuples,
1942
+ ifexpr, etc. Also it would be great to have support for inference on
1943
+ str.split()
1944
+ """
1945
+ __implements__ = IAstroidChecker
1946
+
1947
+ name = 'multiple_types'
1948
+ msgs = {'R0204': ('Redefinition of %s type from %s to %s',
1949
+ 'redefined-variable-type',
1950
+ 'Used when the type of a variable changes inside a '
1951
+ 'method or a function.'
1952
+ ),
1953
+ }
1954
+
1955
+ def visit_classdef(self, _):
1956
+ self._assigns.append({})
1957
+
1958
+ @check_messages('redefined-variable-type')
1959
+ def leave_classdef(self, _):
1960
+ self._check_and_add_messages()
1961
+
1962
+ visit_functiondef = visit_classdef
1963
+ leave_functiondef = leave_module = leave_classdef
1964
+
1965
+ def visit_module(self, _):
1966
+ self._assigns = [{}]
1967
+
1968
+ def _check_and_add_messages(self):
1969
+ assigns = self._assigns.pop()
1970
+ for name, args in assigns.items():
1971
+ if len(args) <= 1:
1972
+ continue
1973
+ _, orig_type = args[0]
1974
+ # Check if there is a type in the following nodes that would be
1975
+ # different from orig_type.
1976
+ for redef_node, redef_type in args[1:]:
1977
+ if redef_type != orig_type:
1978
+ orig_type = orig_type.replace(BUILTINS + ".", '')
1979
+ redef_type = redef_type.replace(BUILTINS + ".", '')
1980
+ self.add_message('redefined-variable-type', node=redef_node,
1981
+ args=(name, orig_type, redef_type))
1982
+ break
1983
+
1984
+ def visit_assign(self, node):
1985
+ # we don't handle multiple assignment nor slice assignment
1986
+ target = node.targets[0]
1987
+ if isinstance(target, (astroid.Tuple, astroid.Subscript)):
1988
+ return
1989
+ # ignore NoneType
1990
+ if _is_none(node):
1991
+ return
1992
+ _type = _node_type(node.value)
1993
+ if _type:
1994
+ self._assigns[-1].setdefault(target.as_string(), []).append(
1995
+ (node, _type.pytype()))
1996
+
1997
+
1229
1998
  def register(linter):
1230
1999
  """required method to auto register this checker"""
1231
2000
  linter.register_checker(BasicErrorChecker(linter))
@@ -1234,3 +2003,8 @@ def register(linter):
1234
2003
  linter.register_checker(DocStringChecker(linter))
1235
2004
  linter.register_checker(PassChecker(linter))
1236
2005
  linter.register_checker(LambdaForComprehensionChecker(linter))
2006
+ linter.register_checker(ComparisonChecker(linter))
2007
+ linter.register_checker(NotChecker(linter))
2008
+ linter.register_checker(RecommandationChecker(linter))
2009
+ linter.register_checker(ElifChecker(linter))
2010
+ linter.register_checker(MultipleTypesChecker(linter))