deadcode 2.3.0__py3-none-any.whl → 2.3.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (338) hide show
  1. deadcode/actions/find_python_filenames.py +6 -6
  2. deadcode/actions/fix_or_show_unused_code.py +21 -14
  3. deadcode/actions/get_unused_names_error_message.py +6 -6
  4. deadcode/actions/merge_overlaping_file_parts.py +2 -7
  5. deadcode/actions/parse_abstract_syntax_tree.py +1 -1
  6. deadcode/actions/parse_arguments.py +87 -87
  7. deadcode/actions/remove_file_parts_from_content.py +36 -19
  8. deadcode/cli.py +3 -3
  9. deadcode/constants.py +36 -36
  10. deadcode/data_types.py +1 -1
  11. deadcode/utils/add_colors_to_diff.py +7 -7
  12. deadcode/{tests/base.py → utils/base_test_case.py} +18 -18
  13. deadcode/utils/fix_indent.py +63 -29
  14. deadcode/utils/flatten_lists.py +2 -2
  15. deadcode/utils/nested_scopes.py +2 -2
  16. deadcode/utils/print_ast.py +1 -1
  17. deadcode/visitor/code_item.py +15 -28
  18. deadcode/visitor/dead_code_visitor.py +62 -65
  19. deadcode/visitor/ignore.py +29 -29
  20. deadcode/visitor/lines.py +3 -3
  21. deadcode/visitor/noqa.py +33 -33
  22. deadcode/visitor/utils.py +1 -1
  23. {deadcode-2.3.0.dist-info → deadcode-2.3.2.dist-info}/METADATA +35 -16
  24. deadcode-2.3.2.dist-info/RECORD +32 -0
  25. {deadcode-2.3.0.dist-info → deadcode-2.3.2.dist-info}/WHEEL +1 -1
  26. black/action/main.py +0 -176
  27. black/docs/conf.py +0 -218
  28. black/gallery/gallery.py +0 -294
  29. black/profiling/dict_big.py +0 -8001
  30. black/profiling/dict_huge.py +0 -41440
  31. black/profiling/list_big.py +0 -4000
  32. black/profiling/list_huge.py +0 -22431
  33. black/profiling/mix_big.py +0 -1002
  34. black/profiling/mix_huge.py +0 -7692
  35. black/profiling/mix_small.py +0 -102
  36. black/scripts/__init__.py +0 -0
  37. black/scripts/check_pre_commit_rev_in_example.py +0 -54
  38. black/scripts/check_version_in_basics_example.py +0 -48
  39. black/scripts/diff_shades_gha_helper.py +0 -236
  40. black/scripts/fuzz.py +0 -92
  41. black/scripts/generate_schema.py +0 -74
  42. black/scripts/make_width_table.py +0 -66
  43. black/scripts/migrate-black.py +0 -96
  44. black/scripts/release.py +0 -245
  45. black/scripts/release_tests.py +0 -69
  46. black/src/black/__init__.py +0 -1605
  47. black/src/black/__main__.py +0 -3
  48. black/src/black/_width_table.py +0 -478
  49. black/src/black/brackets.py +0 -382
  50. black/src/black/cache.py +0 -150
  51. black/src/black/comments.py +0 -415
  52. black/src/black/concurrency.py +0 -190
  53. black/src/black/const.py +0 -4
  54. black/src/black/debug.py +0 -54
  55. black/src/black/files.py +0 -433
  56. black/src/black/handle_ipynb_magics.py +0 -452
  57. black/src/black/linegen.py +0 -1745
  58. black/src/black/lines.py +0 -1073
  59. black/src/black/mode.py +0 -265
  60. black/src/black/nodes.py +0 -1007
  61. black/src/black/numerics.py +0 -61
  62. black/src/black/output.py +0 -122
  63. black/src/black/parsing.py +0 -244
  64. black/src/black/ranges.py +0 -521
  65. black/src/black/report.py +0 -107
  66. black/src/black/resources/__init__.py +0 -0
  67. black/src/black/rusty.py +0 -28
  68. black/src/black/schema.py +0 -20
  69. black/src/black/strings.py +0 -325
  70. black/src/black/trans.py +0 -2534
  71. black/src/blackd/__init__.py +0 -259
  72. black/src/blackd/__main__.py +0 -3
  73. black/src/blackd/middlewares.py +0 -45
  74. black/src/blib2to3/__init__.py +0 -1
  75. black/src/blib2to3/pgen2/__init__.py +0 -4
  76. black/src/blib2to3/pgen2/conv.py +0 -256
  77. black/src/blib2to3/pgen2/driver.py +0 -316
  78. black/src/blib2to3/pgen2/grammar.py +0 -227
  79. black/src/blib2to3/pgen2/literals.py +0 -66
  80. black/src/blib2to3/pgen2/parse.py +0 -411
  81. black/src/blib2to3/pgen2/pgen.py +0 -428
  82. black/src/blib2to3/pgen2/token.py +0 -88
  83. black/src/blib2to3/pgen2/tokenize.py +0 -698
  84. black/src/blib2to3/pygram.py +0 -200
  85. black/src/blib2to3/pytree.py +0 -986
  86. black/tests/__init__.py +0 -0
  87. black/tests/conftest.py +0 -28
  88. black/tests/data/cases/allow_empty_first_line.py +0 -166
  89. black/tests/data/cases/async_stmts.py +0 -27
  90. black/tests/data/cases/attribute_access_on_number_literals.py +0 -47
  91. black/tests/data/cases/beginning_backslash.py +0 -12
  92. black/tests/data/cases/bracketmatch.py +0 -15
  93. black/tests/data/cases/bytes_docstring.py +0 -34
  94. black/tests/data/cases/class_blank_parentheses.py +0 -59
  95. black/tests/data/cases/class_methods_new_line.py +0 -270
  96. black/tests/data/cases/collections.py +0 -174
  97. black/tests/data/cases/comment_after_escaped_newline.py +0 -18
  98. black/tests/data/cases/comment_type_hint.py +0 -3
  99. black/tests/data/cases/comments.py +0 -96
  100. black/tests/data/cases/comments2.py +0 -344
  101. black/tests/data/cases/comments3.py +0 -48
  102. black/tests/data/cases/comments4.py +0 -94
  103. black/tests/data/cases/comments5.py +0 -70
  104. black/tests/data/cases/comments6.py +0 -118
  105. black/tests/data/cases/comments8.py +0 -15
  106. black/tests/data/cases/comments9.py +0 -305
  107. black/tests/data/cases/comments_in_blocks.py +0 -111
  108. black/tests/data/cases/comments_in_double_parens.py +0 -113
  109. black/tests/data/cases/comments_non_breaking_space.py +0 -44
  110. black/tests/data/cases/composition.py +0 -181
  111. black/tests/data/cases/composition_no_trailing_comma.py +0 -367
  112. black/tests/data/cases/conditional_expression.py +0 -204
  113. black/tests/data/cases/context_managers_38.py +0 -55
  114. black/tests/data/cases/context_managers_39.py +0 -175
  115. black/tests/data/cases/context_managers_autodetect_310.py +0 -36
  116. black/tests/data/cases/context_managers_autodetect_311.py +0 -38
  117. black/tests/data/cases/context_managers_autodetect_38.py +0 -46
  118. black/tests/data/cases/context_managers_autodetect_39.py +0 -35
  119. black/tests/data/cases/docstring.py +0 -457
  120. black/tests/data/cases/docstring_newline_preview.py +0 -4
  121. black/tests/data/cases/docstring_no_extra_empty_line_before_eof.py +0 -4
  122. black/tests/data/cases/docstring_no_string_normalization.py +0 -250
  123. black/tests/data/cases/docstring_preview.py +0 -104
  124. black/tests/data/cases/dummy_implementations.py +0 -144
  125. black/tests/data/cases/empty_lines.py +0 -187
  126. black/tests/data/cases/expression.py +0 -630
  127. black/tests/data/cases/f_docstring.py +0 -20
  128. black/tests/data/cases/fmtonoff.py +0 -409
  129. black/tests/data/cases/fmtonoff2.py +0 -40
  130. black/tests/data/cases/fmtonoff3.py +0 -35
  131. black/tests/data/cases/fmtonoff4.py +0 -36
  132. black/tests/data/cases/fmtonoff5.py +0 -175
  133. black/tests/data/cases/fmtpass_imports.py +0 -19
  134. black/tests/data/cases/fmtskip.py +0 -3
  135. black/tests/data/cases/fmtskip2.py +0 -20
  136. black/tests/data/cases/fmtskip3.py +0 -20
  137. black/tests/data/cases/fmtskip4.py +0 -13
  138. black/tests/data/cases/fmtskip5.py +0 -22
  139. black/tests/data/cases/fmtskip6.py +0 -13
  140. black/tests/data/cases/fmtskip7.py +0 -11
  141. black/tests/data/cases/fmtskip8.py +0 -62
  142. black/tests/data/cases/fmtskip9.py +0 -9
  143. black/tests/data/cases/form_feeds.py +0 -226
  144. black/tests/data/cases/fstring.py +0 -25
  145. black/tests/data/cases/funcdef_return_type_trailing_comma.py +0 -301
  146. black/tests/data/cases/function.py +0 -244
  147. black/tests/data/cases/function2.py +0 -121
  148. black/tests/data/cases/function_trailing_comma.py +0 -178
  149. black/tests/data/cases/ignore_pyi.py +0 -42
  150. black/tests/data/cases/import_spacing.py +0 -118
  151. black/tests/data/cases/is_simple_lookup_for_doublestar_expression.py +0 -14
  152. black/tests/data/cases/keep_newline_after_match.py +0 -41
  153. black/tests/data/cases/line_ranges_basic.py +0 -107
  154. black/tests/data/cases/line_ranges_diff_edge_case.py +0 -28
  155. black/tests/data/cases/line_ranges_exceeding_end.py +0 -36
  156. black/tests/data/cases/line_ranges_fmt_off.py +0 -49
  157. black/tests/data/cases/line_ranges_fmt_off_decorator.py +0 -47
  158. black/tests/data/cases/line_ranges_fmt_off_overlap.py +0 -37
  159. black/tests/data/cases/line_ranges_imports.py +0 -9
  160. black/tests/data/cases/line_ranges_indentation.py +0 -27
  161. black/tests/data/cases/line_ranges_outside_source.py +0 -7
  162. black/tests/data/cases/line_ranges_two_passes.py +0 -27
  163. black/tests/data/cases/line_ranges_unwrapping.py +0 -25
  164. black/tests/data/cases/linelength6.py +0 -6
  165. black/tests/data/cases/long_strings_flag_disabled.py +0 -296
  166. black/tests/data/cases/module_docstring_1.py +0 -25
  167. black/tests/data/cases/module_docstring_2.py +0 -70
  168. black/tests/data/cases/module_docstring_3.py +0 -7
  169. black/tests/data/cases/module_docstring_4.py +0 -8
  170. black/tests/data/cases/module_docstring_followed_by_class.py +0 -10
  171. black/tests/data/cases/module_docstring_followed_by_function.py +0 -10
  172. black/tests/data/cases/multiline_consecutive_open_parentheses_ignore.py +0 -41
  173. black/tests/data/cases/nested_stub.py +0 -69
  174. black/tests/data/cases/no_blank_line_before_docstring.py +0 -66
  175. black/tests/data/cases/numeric_literals.py +0 -39
  176. black/tests/data/cases/numeric_literals_skip_underscores.py +0 -19
  177. black/tests/data/cases/one_element_subscript.py +0 -36
  178. black/tests/data/cases/parenthesized_context_managers.py +0 -46
  179. black/tests/data/cases/pattern_matching_complex.py +0 -155
  180. black/tests/data/cases/pattern_matching_extras.py +0 -102
  181. black/tests/data/cases/pattern_matching_generic.py +0 -108
  182. black/tests/data/cases/pattern_matching_long.py +0 -34
  183. black/tests/data/cases/pattern_matching_simple.py +0 -93
  184. black/tests/data/cases/pattern_matching_style.py +0 -92
  185. black/tests/data/cases/pattern_matching_trailing_comma.py +0 -39
  186. black/tests/data/cases/pattern_matching_with_if_stmt.py +0 -72
  187. black/tests/data/cases/pep604_union_types_line_breaks.py +0 -188
  188. black/tests/data/cases/pep_570.py +0 -45
  189. black/tests/data/cases/pep_572.py +0 -48
  190. black/tests/data/cases/pep_572_do_not_remove_parens.py +0 -26
  191. black/tests/data/cases/pep_572_py310.py +0 -16
  192. black/tests/data/cases/pep_572_py39.py +0 -8
  193. black/tests/data/cases/pep_572_remove_parens.py +0 -142
  194. black/tests/data/cases/pep_572_slices.py +0 -6
  195. black/tests/data/cases/pep_604.py +0 -25
  196. black/tests/data/cases/pep_646.py +0 -195
  197. black/tests/data/cases/pep_654.py +0 -54
  198. black/tests/data/cases/pep_654_style.py +0 -112
  199. black/tests/data/cases/percent_precedence.py +0 -41
  200. black/tests/data/cases/power_op_newline.py +0 -11
  201. black/tests/data/cases/power_op_spacing.py +0 -149
  202. black/tests/data/cases/power_op_spacing_long.py +0 -96
  203. black/tests/data/cases/prefer_rhs_split.py +0 -106
  204. black/tests/data/cases/prefer_rhs_split_reformatted.py +0 -38
  205. black/tests/data/cases/preview_cantfit.py +0 -94
  206. black/tests/data/cases/preview_cantfit_string.py +0 -18
  207. black/tests/data/cases/preview_comments7.py +0 -309
  208. black/tests/data/cases/preview_format_unicode_escape_seq.py +0 -34
  209. black/tests/data/cases/preview_hug_parens_with_braces_and_square_brackets.py +0 -347
  210. black/tests/data/cases/preview_hug_parens_with_braces_and_square_brackets_no_ll1.py +0 -106
  211. black/tests/data/cases/preview_long_dict_values.py +0 -129
  212. black/tests/data/cases/preview_long_strings.py +0 -928
  213. black/tests/data/cases/preview_long_strings__east_asian_width.py +0 -26
  214. black/tests/data/cases/preview_long_strings__edge_case.py +0 -141
  215. black/tests/data/cases/preview_long_strings__regression.py +0 -1247
  216. black/tests/data/cases/preview_long_strings__type_annotations.py +0 -60
  217. black/tests/data/cases/preview_multiline_strings.py +0 -401
  218. black/tests/data/cases/preview_return_annotation_brackets_string.py +0 -24
  219. black/tests/data/cases/py310_pep572.py +0 -13
  220. black/tests/data/cases/python37.py +0 -62
  221. black/tests/data/cases/python38.py +0 -42
  222. black/tests/data/cases/python39.py +0 -30
  223. black/tests/data/cases/raw_docstring.py +0 -32
  224. black/tests/data/cases/raw_docstring_no_string_normalization.py +0 -11
  225. black/tests/data/cases/remove_await_parens.py +0 -195
  226. black/tests/data/cases/remove_except_parens.py +0 -79
  227. black/tests/data/cases/remove_for_brackets.py +0 -48
  228. black/tests/data/cases/remove_newline_after_code_block_open.py +0 -212
  229. black/tests/data/cases/remove_parens.py +0 -142
  230. black/tests/data/cases/remove_redundant_parens_in_case_guard.py +0 -114
  231. black/tests/data/cases/remove_with_brackets.py +0 -120
  232. black/tests/data/cases/return_annotation_brackets.py +0 -219
  233. black/tests/data/cases/single_line_format_skip_with_multiple_comments.py +0 -19
  234. black/tests/data/cases/skip_magic_trailing_comma.py +0 -75
  235. black/tests/data/cases/slices.py +0 -31
  236. black/tests/data/cases/split_delimiter_comments.py +0 -51
  237. black/tests/data/cases/starred_for_target.py +0 -28
  238. black/tests/data/cases/string_prefixes.py +0 -45
  239. black/tests/data/cases/stub.py +0 -152
  240. black/tests/data/cases/torture.py +0 -91
  241. black/tests/data/cases/trailing_comma.py +0 -55
  242. black/tests/data/cases/trailing_comma_optional_parens1.py +0 -63
  243. black/tests/data/cases/trailing_comma_optional_parens2.py +0 -12
  244. black/tests/data/cases/trailing_comma_optional_parens3.py +0 -21
  245. black/tests/data/cases/trailing_commas_in_leading_parts.py +0 -88
  246. black/tests/data/cases/tricky_unicode_symbols.py +0 -9
  247. black/tests/data/cases/tupleassign.py +0 -23
  248. black/tests/data/cases/type_aliases.py +0 -30
  249. black/tests/data/cases/type_comment_syntax_error.py +0 -11
  250. black/tests/data/cases/type_params.py +0 -58
  251. black/tests/data/cases/typed_params_trailing_comma.py +0 -24
  252. black/tests/data/cases/walrus_in_dict.py +0 -9
  253. black/tests/data/cases/whitespace.py +0 -6
  254. black/tests/data/gitignore_used_on_multiple_sources/dir1/a.py +0 -0
  255. black/tests/data/gitignore_used_on_multiple_sources/dir1/b.py +0 -0
  256. black/tests/data/gitignore_used_on_multiple_sources/dir2/a.py +0 -0
  257. black/tests/data/gitignore_used_on_multiple_sources/dir2/b.py +0 -0
  258. black/tests/data/ignore_subfolders_gitignore_tests/a.py +0 -0
  259. black/tests/data/ignore_subfolders_gitignore_tests/subdir/b.py +0 -0
  260. black/tests/data/ignore_subfolders_gitignore_tests/subdir/subdir/c.py +0 -0
  261. black/tests/data/include_exclude_tests/b/.definitely_exclude/a.py +0 -0
  262. black/tests/data/include_exclude_tests/b/dont_exclude/a.py +0 -0
  263. black/tests/data/include_exclude_tests/b/exclude/a.py +0 -0
  264. black/tests/data/invalid_gitignore_tests/a.py +0 -0
  265. black/tests/data/invalid_nested_gitignore_tests/a/a.py +0 -0
  266. black/tests/data/invalid_nested_gitignore_tests/a.py +0 -0
  267. black/tests/data/line_ranges_formatted/basic.py +0 -50
  268. black/tests/data/line_ranges_formatted/pattern_matching.py +0 -25
  269. black/tests/data/miscellaneous/async_as_identifier.py +0 -49
  270. black/tests/data/miscellaneous/blackd_diff.py +0 -6
  271. black/tests/data/miscellaneous/debug_visitor.py +0 -32
  272. black/tests/data/miscellaneous/decorators.py +0 -182
  273. black/tests/data/miscellaneous/force_py36.py +0 -16
  274. black/tests/data/miscellaneous/force_pyi.py +0 -66
  275. black/tests/data/miscellaneous/invalid_header.py +0 -2
  276. black/tests/data/miscellaneous/missing_final_newline.py +0 -3
  277. black/tests/data/miscellaneous/pattern_matching_invalid.py +0 -18
  278. black/tests/data/miscellaneous/python2_detection.py +0 -90
  279. black/tests/data/miscellaneous/string_quotes.py +0 -114
  280. black/tests/data/nested_gitignore_tests/root/a.py +0 -1
  281. black/tests/data/nested_gitignore_tests/root/b.py +0 -1
  282. black/tests/data/nested_gitignore_tests/root/c.py +0 -1
  283. black/tests/data/nested_gitignore_tests/root/child/a.py +0 -1
  284. black/tests/data/nested_gitignore_tests/root/child/b.py +0 -1
  285. black/tests/data/nested_gitignore_tests/root/child/c.py +0 -1
  286. black/tests/data/nested_gitignore_tests/x.py +0 -0
  287. black/tests/optional.py +0 -132
  288. black/tests/test_black.py +0 -2980
  289. black/tests/test_blackd.py +0 -248
  290. black/tests/test_docs.py +0 -74
  291. black/tests/test_format.py +0 -90
  292. black/tests/test_ipynb.py +0 -517
  293. black/tests/test_no_ipynb.py +0 -36
  294. black/tests/test_ranges.py +0 -249
  295. black/tests/test_schema.py +0 -17
  296. black/tests/test_trans.py +0 -51
  297. black/tests/util.py +0 -354
  298. call_arg_map_to_parameters_poc.py +0 -173
  299. deadcode/tests/actions/test_find_python_filenames.py +0 -36
  300. deadcode/tests/actions/test_merge_overlaping_file_parts.py +0 -62
  301. deadcode/tests/cli_args/test_count.py +0 -0
  302. deadcode/tests/cli_args/test_dry.py +0 -318
  303. deadcode/tests/cli_args/test_exclude.py +0 -24
  304. deadcode/tests/cli_args/test_fix.py +0 -528
  305. deadcode/tests/cli_args/test_ignore_bodies_if_inherits_from.py +0 -46
  306. deadcode/tests/cli_args/test_ignore_definitions.py +0 -106
  307. deadcode/tests/cli_args/test_ignore_definitions_if_inherits_from.py +0 -125
  308. deadcode/tests/cli_args/test_ignore_names.py +0 -79
  309. deadcode/tests/cli_args/test_ignore_names_in_files.py +0 -0
  310. deadcode/tests/cli_args/test_no_color.py +0 -0
  311. deadcode/tests/cli_args/test_parsing.py +0 -113
  312. deadcode/tests/cli_args/test_quiet.py +0 -0
  313. deadcode/tests/cli_args/test_verbose.py +0 -0
  314. deadcode/tests/code_item/test_code_item.py +0 -16
  315. deadcode/tests/files/classes.py +0 -15
  316. deadcode/tests/files/functions.py +0 -21
  317. deadcode/tests/files/subdir/another_subdir/__init__.py +0 -1
  318. deadcode/tests/files/subdir/one_more_file.py +0 -2
  319. deadcode/tests/files/variables.py +0 -8
  320. deadcode/tests/fix/test_assign.py +0 -92
  321. deadcode/tests/fix/test_class_def.py +0 -116
  322. deadcode/tests/fix/test_empty_files.py +0 -36
  323. deadcode/tests/fix/test_method_def.py +0 -66
  324. deadcode/tests/fix/test_scope.py +0 -243
  325. deadcode/tests/fix/test_unreachable_code.py +0 -100
  326. deadcode/tests/nested_scope/test_nested_scope.py +0 -180
  327. deadcode/tests/noqa/test_noqa_comments.py +0 -329
  328. deadcode/tests/test_accurate_usage_detection.py +0 -49
  329. deadcode/tests/test_deadcode.py +0 -68
  330. deadcode/tests/test_imports.py +0 -101
  331. deadcode/tests/test_line_number_detection.py +0 -97
  332. deadcode/tests/test_output.py +0 -137
  333. deadcode/tests/test_variable_parsing_from_ast_dump.py +0 -12
  334. deadcode/tests/utils/test_add_colors_to_diff.py +0 -38
  335. deadcode/tests/utils/test_fix_indent.py +0 -10
  336. deadcode-2.3.0.dist-info/RECORD +0 -342
  337. {deadcode-2.3.0.dist-info → deadcode-2.3.2.dist-info}/entry_points.txt +0 -0
  338. {deadcode-2.3.0.dist-info → deadcode-2.3.2.dist-info}/licenses/LICENSE +0 -0
@@ -16,21 +16,21 @@ def find_python_filenames(args: Args) -> List[str]:
16
16
 
17
17
  if _match(path, args.exclude):
18
18
  if args.verbose:
19
- logger.info(f"Ignoring: {path}")
19
+ logger.info(f'Ignoring: {path}')
20
20
  continue
21
21
 
22
- if path.is_file() and path.suffix == ".py":
22
+ if path.is_file() and path.suffix == '.py':
23
23
  filenames.append(str(path))
24
24
  elif path.is_dir():
25
- paths += list([str(p) for p in path.glob("*")])
25
+ paths += list([str(p) for p in path.glob('*')])
26
26
  elif not path.exists():
27
27
  # TODO: unify error logging and reporting
28
28
  # Maybe a cli flag could be added to stop on error
29
- logger.error(f"Error: {path} could not be found.")
29
+ logger.error(f'Error: {path} could not be found.')
30
30
 
31
31
  if args.verbose:
32
- sep = "\n - "
33
- logger.info(f"Files to be checked for dead code: {sep.join(filenames)}")
32
+ sep = '\n - '
33
+ logger.info(f'Files to be checked for dead code: {sep.join(filenames)}')
34
34
  return filenames
35
35
 
36
36
 
@@ -1,5 +1,5 @@
1
1
  from collections import defaultdict
2
- from difflib import unified_diff
2
+ from difflib import diff_bytes, unified_diff
3
3
  from typing import Iterable
4
4
  import os
5
5
 
@@ -27,37 +27,44 @@ def fix_or_show_unused_code(unused_items: Iterable[CodeItem], args: Args) -> str
27
27
 
28
28
  result = []
29
29
 
30
- for filename, unused_items in filename_to_unused_items.items():
31
- file_parts = flatten_list([item.code_parts for item in unused_items])
30
+ for filename, file_unused_items in filename_to_unused_items.items():
31
+ file_parts = flatten_list([item.code_parts for item in file_unused_items])
32
32
 
33
33
  unused_file_parts = merge_overlaping_file_parts(file_parts)
34
34
 
35
- with open(filename) as f:
35
+ with open(filename, 'rb') as f:
36
36
  file_content_lines = f.readlines()
37
37
 
38
38
  updated_file_content_lines = remove_file_parts_from_content(file_content_lines, unused_file_parts)
39
- updated_file_content = "".join(updated_file_content_lines)
39
+ updated_file_content = b''.join(updated_file_content_lines)
40
40
  if updated_file_content.strip():
41
- if args.dry and ("__all_files__" in args.dry or _match(filename, args.dry)):
42
- with open(filename, "r") as f:
43
- diff = unified_diff(f.readlines(), updated_file_content_lines, fromfile=filename, tofile=filename)
41
+ if args.dry and ('__all_files__' in args.dry or _match(filename, args.dry)):
42
+ with open(filename, 'rb') as f:
43
+ filename_bytes = filename.encode()
44
+ diff = diff_bytes(
45
+ unified_diff,
46
+ f.readlines(),
47
+ updated_file_content_lines,
48
+ fromfile=filename_bytes,
49
+ tofile=filename_bytes,
50
+ )
44
51
  # TODO: consider printing result instantly to save memory
45
- diff_str = "".join(diff)
52
+ result_chunk = b''.join(diff)
46
53
  if args.no_color:
47
- result.append(diff_str)
54
+ result.append(result_chunk)
48
55
  else:
49
- result.append(add_colors_to_diff(diff_str))
56
+ result.append(add_colors_to_diff(result_chunk))
50
57
 
51
58
  elif args.fix:
52
- with open(filename, "w") as f:
59
+ with open(filename, 'wb') as f:
53
60
  # TODO: is there a method writelines?
54
61
  f.write(updated_file_content)
55
62
  else:
56
63
  os.remove(filename)
57
64
 
58
65
  if result:
59
- return "\n".join(result)
60
- return ""
66
+ return b'\n'.join(result).decode()
67
+ return ''
61
68
 
62
69
  # TODO: update this one: solution is to use read and write operations.
63
70
  #
@@ -11,25 +11,25 @@ def get_unused_names_error_message(unused_names: Iterable[CodeItem], args: Args)
11
11
  return None
12
12
 
13
13
  if args.quiet:
14
- return ""
14
+ return ''
15
15
 
16
16
  if args.count:
17
- return f"{len(unused_names)}"
17
+ return f'{len(unused_names)}'
18
18
 
19
19
  messages = []
20
20
  for item in unused_names:
21
- message = f"{item.filename_with_position} \033[91m{item.error_code}\033[0m "
21
+ message = f'{item.filename_with_position} \033[91m{item.error_code}\033[0m '
22
22
  message += item.message or (
23
23
  f"{item.type_.replace('_', ' ').capitalize()} " f"`\033[1m{item.name}\033[0m` " f"is never used"
24
24
  )
25
25
  if args.no_color:
26
- message = message.replace("\033[91m", "").replace("\033[1m", "").replace("\033[0m", "")
26
+ message = message.replace('\033[91m', '').replace('\033[1m', '').replace('\033[0m', '')
27
27
  messages.append(message)
28
28
 
29
29
  if args.fix:
30
30
  message = f"\nRemoved \033[1m{len(unused_names)}\033[0m unused code item{'s' if len(unused_names) > 1 else ''}!"
31
31
  if args.no_color:
32
- message = message.replace("\x1b[1m", "").replace("\x1b[0m", "")
32
+ message = message.replace('\x1b[1m', '').replace('\x1b[0m', '')
33
33
  messages.append(message)
34
34
 
35
- return "\n".join(messages)
35
+ return '\n'.join(messages)
@@ -10,9 +10,7 @@ def does_include(bigger_part: Part, smaller_part: Part) -> bool:
10
10
 
11
11
  ends_faster = (line_end_b < line_end_s) or ((line_end_b == line_end_b) and (col_end_b <= col_end_s))
12
12
 
13
- if starts_later and ends_faster:
14
- return True
15
- return False
13
+ return bool(starts_later and ends_faster)
16
14
 
17
15
 
18
16
  def sort_parts(bigger_part: Part, smaller_part: Part) -> Tuple[Part, Part]:
@@ -34,10 +32,7 @@ def does_overlap(bigger_part: Part, smaller_part: Part) -> bool:
34
32
  line_start_s, line_end_s, col_start_s, col_end_s = smaller_part
35
33
 
36
34
  # ar pirmo pabaiga perlipa antro pradžia
37
- if (line_end_b > line_start_s) or ((line_end_b == line_start_s) and (col_end_b > col_start_s)):
38
- return True
39
-
40
- return False
35
+ return bool((line_end_b > line_start_s) or ((line_end_b == line_start_s) and (col_end_b > col_start_s)))
41
36
 
42
37
 
43
38
  def merge_parts(p1: Part, p2: Part) -> Optional[Part]:
@@ -9,5 +9,5 @@ def parse_abstract_syntax_tree(file_content: FileContent, args: Args, filename:
9
9
  return ast.parse(file_content, filename=filename, type_comments=True)
10
10
  except: # noqa: E722
11
11
  if not args.count and not args.quiet:
12
- print(f"Error: Failed to parse {filename} file, ignoring it.")
12
+ print(f'Error: Failed to parse {filename} file, ignoring it.')
13
13
  return ast.Module()
@@ -26,173 +26,173 @@ def parse_arguments(args: Optional[List[str]]) -> Args:
26
26
 
27
27
  # Docs: https://docs.python.org/3/library/argparse.html
28
28
  parser = argparse.ArgumentParser()
29
- parser.add_argument("paths", help="Paths where to search for python files", nargs="+")
29
+ parser.add_argument('paths', help='Paths where to search for python files', nargs='+')
30
30
  parser.add_argument(
31
- "--fix",
32
- help="Automatically remove detected unused code expressions from the code base.",
33
- action="store_true",
31
+ '--fix',
32
+ help='Automatically remove detected unused code expressions from the code base.',
33
+ action='store_true',
34
34
  default=False,
35
35
  )
36
36
  parser.add_argument(
37
- "--dry",
38
- help="Show changes which would be made in files with --fix option.",
39
- nargs="*",
40
- action="append",
41
- default=[["__all_files__"]],
37
+ '--dry',
38
+ help='Show changes which would be made in files with --fix option.',
39
+ nargs='*',
40
+ action='append',
41
+ default=[['__all_files__']],
42
42
  type=str,
43
43
  )
44
44
  parser.add_argument(
45
- "--exclude",
46
- help="Filenames (or path expressions), which will be completely skipped without being analysed.",
47
- nargs="*",
48
- action="append",
45
+ '--exclude',
46
+ help='Filenames (or path expressions), which will be completely skipped without being analysed.',
47
+ nargs='*',
48
+ action='append',
49
49
  default=[],
50
50
  type=str,
51
51
  )
52
52
  parser.add_argument(
53
- "--ignore-names",
53
+ '--ignore-names',
54
54
  help=(
55
- "Removes provided list of names from the output. "
56
- "Regexp expressions to match multiple names can also be provided."
55
+ 'Removes provided list of names from the output. '
56
+ 'Regexp expressions to match multiple names can also be provided.'
57
57
  ),
58
- nargs="*",
59
- action="append",
58
+ nargs='*',
59
+ action='append',
60
60
  default=[],
61
61
  type=str,
62
62
  )
63
63
  parser.add_argument(
64
- "--ignore-bodies-of",
65
- help="Ignores body of an expression if its name matches any of the provided names.",
66
- nargs="*",
67
- action="append",
64
+ '--ignore-bodies-of',
65
+ help='Ignores body of an expression if its name matches any of the provided names.',
66
+ nargs='*',
67
+ action='append',
68
68
  default=[],
69
69
  type=str,
70
70
  )
71
71
  parser.add_argument(
72
- "--ignore-bodies-if-decorated-with",
73
- help="Ignores body of an expression if its decorated with one of the provided decorator names.",
74
- nargs="*",
75
- action="append",
72
+ '--ignore-bodies-if-decorated-with',
73
+ help='Ignores body of an expression if its decorated with one of the provided decorator names.',
74
+ nargs='*',
75
+ action='append',
76
76
  default=[],
77
77
  type=str,
78
78
  )
79
79
  parser.add_argument(
80
- "--ignore-bodies-if-inherits-from",
81
- help="Ignores body of a class if it inherits from any of the provided class names.",
82
- nargs="*",
83
- action="append",
80
+ '--ignore-bodies-if-inherits-from',
81
+ help='Ignores body of a class if it inherits from any of the provided class names.',
82
+ nargs='*',
83
+ action='append',
84
84
  default=[],
85
85
  type=str,
86
86
  )
87
87
  parser.add_argument(
88
- "--ignore-definitions",
88
+ '--ignore-definitions',
89
89
  help=(
90
- "Ignores definition (including name and body) if a "
91
- "name of an expression matches any of the provided ones."
90
+ 'Ignores definition (including name and body) if a '
91
+ 'name of an expression matches any of the provided ones.'
92
92
  ),
93
- nargs="*",
94
- action="append",
93
+ nargs='*',
94
+ action='append',
95
95
  default=[],
96
96
  type=str,
97
97
  )
98
98
  parser.add_argument(
99
- "--ignore-definitions-if-inherits-from",
99
+ '--ignore-definitions-if-inherits-from',
100
100
  help=(
101
- "Ignores definition (including name and body) of a class if "
102
- "it inherits from any of the provided class names."
101
+ 'Ignores definition (including name and body) of a class if '
102
+ 'it inherits from any of the provided class names.'
103
103
  ),
104
- nargs="*",
105
- action="append",
104
+ nargs='*',
105
+ action='append',
106
106
  default=[],
107
107
  type=str,
108
108
  )
109
109
  parser.add_argument(
110
- "--ignore-definitions-if-decorated-with",
110
+ '--ignore-definitions-if-decorated-with',
111
111
  help=(
112
- "Ignores definition (including name and body) of an expression, "
113
- "which is decorated with any of the provided decorator names."
112
+ 'Ignores definition (including name and body) of an expression, '
113
+ 'which is decorated with any of the provided decorator names.'
114
114
  ),
115
- nargs="*",
116
- action="append",
115
+ nargs='*',
116
+ action='append',
117
117
  default=[],
118
118
  type=str,
119
119
  )
120
120
 
121
121
  parser.add_argument(
122
- "--ignore-if-decorated-with",
123
- help="Ignores both the name and its definition if its decorated with one of the provided decorator names.",
124
- nargs="*",
125
- action="append",
122
+ '--ignore-if-decorated-with',
123
+ help='Ignores both the name and its definition if its decorated with one of the provided decorator names.',
124
+ nargs='*',
125
+ action='append',
126
126
  default=[],
127
127
  type=str,
128
128
  )
129
129
  parser.add_argument(
130
- "--ignore-if-inherits-from",
131
- help="Ignores both the name and its definition if the class inerits from the provided class name.",
132
- nargs="*",
133
- action="append",
130
+ '--ignore-if-inherits-from',
131
+ help='Ignores both the name and its definition if the class inerits from the provided class name.',
132
+ nargs='*',
133
+ action='append',
134
134
  default=[],
135
135
  type=str,
136
136
  )
137
137
 
138
138
  parser.add_argument(
139
- "--ignore-names-if-inherits-from",
140
- help="Ignores names of classes, which inherit from provided class names.",
141
- nargs="*",
142
- action="append",
139
+ '--ignore-names-if-inherits-from',
140
+ help='Ignores names of classes, which inherit from provided class names.',
141
+ nargs='*',
142
+ action='append',
143
143
  default=[],
144
144
  type=str,
145
145
  )
146
146
  parser.add_argument(
147
- "--ignore-names-if-decorated-with",
148
- help="Ignores names of an expression, which is decorated with one of the provided decorator names.",
149
- nargs="*",
150
- action="append",
147
+ '--ignore-names-if-decorated-with',
148
+ help='Ignores names of an expression, which is decorated with one of the provided decorator names.',
149
+ nargs='*',
150
+ action='append',
151
151
  default=[],
152
152
  type=str,
153
153
  )
154
154
 
155
155
  parser.add_argument(
156
- "--ignore-names-in-files",
157
- help="Ignores unused names in files, which filenames match provided path expressions.",
158
- nargs="*",
159
- action="append",
156
+ '--ignore-names-in-files',
157
+ help='Ignores unused names in files, which filenames match provided path expressions.',
158
+ nargs='*',
159
+ action='append',
160
160
  default=[],
161
161
  type=str,
162
162
  )
163
163
 
164
164
  parser.add_argument(
165
- "--no-color",
166
- help="Turn off colors in the output",
167
- action="store_true",
165
+ '--no-color',
166
+ help='Turn off colors in the output',
167
+ action='store_true',
168
168
  default=False,
169
169
  )
170
170
 
171
171
  parser.add_argument(
172
- "--quiet",
173
- help="Does not output anything. Makefile still fails with exit code 1 if unused names are found.",
174
- action="store_true",
172
+ '--quiet',
173
+ help='Does not output anything. Makefile still fails with exit code 1 if unused names are found.',
174
+ action='store_true',
175
175
  default=False,
176
176
  )
177
177
 
178
178
  parser.add_argument(
179
- "--count",
180
- help="Provides the count of the detected unused names instead of printing them all out.",
181
- action="store_true",
179
+ '--count',
180
+ help='Provides the count of the detected unused names instead of printing them all out.',
181
+ action='store_true',
182
182
  default=False,
183
183
  )
184
184
  parser.add_argument(
185
- "-v",
186
- "--verbose",
187
- help="Shows logs useful for debuging",
188
- action="store_true",
185
+ '-v',
186
+ '--verbose',
187
+ help='Shows logs useful for debuging',
188
+ action='store_true',
189
189
  default=False,
190
190
  )
191
191
 
192
192
  parsed_args = parser.parse_args(args).__dict__
193
193
 
194
194
  for arg_name, arg_value in parsed_args.items():
195
- if isinstance(arg_value, list) and arg_name != "paths":
195
+ if isinstance(arg_value, list) and arg_name != 'paths':
196
196
  parsed_args[arg_name] = flatten_lists_of_comma_separated_values(parsed_args.get(arg_name))
197
197
 
198
198
  # Extend the Args with the values provided in the pyproject.toml
@@ -201,12 +201,12 @@ def parse_arguments(args: Optional[List[str]]) -> Args:
201
201
  parsed_args[key].extend(item)
202
202
 
203
203
  # Show changes for only provided files instead of all
204
- if len(parsed_args["dry"]) > 1 or "--dry" not in args:
205
- parsed_args["dry"].remove("__all_files__")
204
+ if len(parsed_args['dry']) > 1 or '--dry' not in args:
205
+ parsed_args['dry'].remove('__all_files__')
206
206
 
207
207
  # Do not fix if dry option is provided:
208
- if parsed_args["dry"]:
209
- parsed_args["fix"] = False
208
+ if parsed_args['dry']:
209
+ parsed_args['fix'] = False
210
210
 
211
211
  return Args(**parsed_args)
212
212
 
@@ -217,13 +217,13 @@ def parse_pyproject_toml() -> Dict[str, Any]:
217
217
  If parsing fails, will raise a tomllib.TOMLDecodeError.
218
218
  Copied from: https://github.com/psf/black/blob/01b8d3d4095ebdb91d0d39012a517931625c63cb/src/black/files.py#LL113C15-L113C15
219
219
  """
220
- pyproject_toml_filename = "pyproject.toml"
220
+ pyproject_toml_filename = 'pyproject.toml'
221
221
  if not os.path.isfile(pyproject_toml_filename):
222
222
  return {}
223
223
 
224
- with open(pyproject_toml_filename, "rb") as f:
224
+ with open(pyproject_toml_filename, 'rb') as f:
225
225
  pyproject_toml = tomllib.load(f)
226
226
 
227
- config: Dict[str, Any] = pyproject_toml.get("tool", {}).get("deadcode", {})
228
- config = {k.replace("--", "").replace("-", "_"): v for k, v in config.items()}
227
+ config: Dict[str, Any] = pyproject_toml.get('tool', {}).get('deadcode', {})
228
+ config = {k.replace('--', '').replace('-', '_'): v for k, v in config.items()}
229
229
  return config
@@ -3,7 +3,7 @@ from typing import List, Optional, TypeVar
3
3
 
4
4
  from deadcode.data_types import Part
5
5
 
6
- T = TypeVar("T")
6
+ T = TypeVar('T')
7
7
 
8
8
 
9
9
  def list_get(list_: List[T], index: int) -> Optional[T]:
@@ -12,20 +12,20 @@ def list_get(list_: List[T], index: int) -> Optional[T]:
12
12
  return None
13
13
 
14
14
 
15
- def ends_with_semicolon(line: str) -> bool:
16
- return line.strip().endswith(":")
15
+ def ends_with_semicolon(line: bytes) -> bool:
16
+ return line.strip().endswith(b':')
17
17
 
18
18
 
19
- def indentation_is_not_childs(previous_line: str, current_line: str) -> bool:
19
+ def indentation_is_not_childs(previous_line: bytes, current_line: bytes) -> bool:
20
20
  return len(get_indentation(previous_line)) >= len(get_indentation(current_line))
21
21
 
22
22
 
23
- def get_indentation(line: str) -> str:
24
- return str(re.findall("^\s*", line)[0])
23
+ def get_indentation(line: bytes) -> bytes:
24
+ return bytes(re.findall(b'^\\s*', line)[0])
25
25
 
26
26
 
27
- def remove_as_from_end(line: str) -> str:
28
- if not (line_rstrip := line.rstrip()).endswith("as"):
27
+ def remove_as_from_end(line: bytes) -> bytes:
28
+ if not (line_rstrip := line.rstrip()).endswith(b'as'):
29
29
  return line
30
30
 
31
31
  # Is there white spaces before as
@@ -34,7 +34,14 @@ def remove_as_from_end(line: str) -> str:
34
34
  return line
35
35
 
36
36
 
37
- def remove_file_parts_from_content(content_lines: List[str], unused_file_parts: List[Part]) -> List[str]:
37
+ def remove_comma_from_begining(line: bytes) -> bytes:
38
+ if not line.lstrip().startswith(b','):
39
+ return line
40
+
41
+ return line.lstrip()[1:].lstrip()
42
+
43
+
44
+ def remove_file_parts_from_content(content_lines: List[bytes], unused_file_parts: List[Part]) -> List[bytes]:
38
45
  """ """
39
46
  # How should move through the lines of content?
40
47
  updated_content_lines = []
@@ -42,12 +49,12 @@ def remove_file_parts_from_content(content_lines: List[str], unused_file_parts:
42
49
  # TODO: iterate by line and crop that line if needed.
43
50
  unused_part_index = 0
44
51
 
45
- previous_non_removed_line = ""
52
+ previous_non_removed_line = b''
46
53
  was_block_removed = False
47
54
  next_line_after_removed_block = None
48
- indentation_of_first_removed_line = ""
49
- empty_lines_in_a_row_list: List[str] = []
50
- empty_lines_before_removed_block_list: List[str] = []
55
+ indentation_of_first_removed_line = b''
56
+ empty_lines_in_a_row_list: List[bytes] = []
57
+ empty_lines_before_removed_block_list: List[bytes] = []
51
58
 
52
59
  for current_lineno, line in enumerate(content_lines, start=1):
53
60
  from_line, to_line, from_col, to_col = 0, 0, 0, 0
@@ -63,10 +70,14 @@ def remove_file_parts_from_content(content_lines: List[str], unused_file_parts:
63
70
  indentation_of_first_removed_line = get_indentation(line)
64
71
 
65
72
  if from_line == to_line:
66
- if (line[:from_col] + line[to_col:]).strip().startswith("="):
73
+ # TODO: this check is a workaround for an assignment expression.
74
+ # Clean-ups have to be applied based on removable expression type.
75
+ if (line[:from_col] + line[to_col:]).strip().startswith(b'='):
67
76
  line = line[:from_col]
68
77
  else:
69
- line = remove_as_from_end(line[:from_col]) + line[to_col:]
78
+ # TODO: should apply `as` removal rule only for particular expression type only
79
+ # as well as comma removal.
80
+ line = remove_as_from_end(line[:from_col]) + remove_comma_from_begining(line[to_col:])
70
81
 
71
82
  unused_part_index += 1
72
83
 
@@ -80,16 +91,22 @@ def remove_file_parts_from_content(content_lines: List[str], unused_file_parts:
80
91
  else:
81
92
  line = line[:from_col]
82
93
 
83
- if line.strip() and not line.startswith("#"):
94
+ if line.strip() and not line.startswith(b'#'):
84
95
  previous_non_removed_line = line
85
96
  updated_content_lines.append(line)
86
97
 
87
98
  # Is it last line, from the block, which have to be ignored?
88
99
  elif current_lineno == to_line:
89
100
  line = line[to_col:]
101
+
102
+ # Remove trailing comma, if we have removed something.
103
+ # TODO: this should be applied only for specific expression types only.
104
+ if line.lstrip().startswith(b','):
105
+ line = line.lstrip()[1:].lstrip()
106
+
90
107
  unused_part_index += 1
91
108
  # TODO: Add tests for case, when comments are added at the start or end of the removed block
92
- if line.strip() and not line.startswith("#"):
109
+ if line.strip() and not line.startswith(b'#'):
93
110
  updated_content_lines.append(line)
94
111
 
95
112
  empty_lines_before_removed_block_list, empty_lines_in_a_row_list = (
@@ -118,7 +135,7 @@ def remove_file_parts_from_content(content_lines: List[str], unused_file_parts:
118
135
  if indentation_is_not_childs(
119
136
  previous_line=previous_non_removed_line, current_line=next_line_after_removed_block
120
137
  ):
121
- updated_content_lines.append(f"{indentation_of_first_removed_line}pass\n")
138
+ updated_content_lines.append(indentation_of_first_removed_line + b'pass\n')
122
139
 
123
140
  # Add empty lines
124
141
  if indentation_is_not_childs(
@@ -144,6 +161,6 @@ def remove_file_parts_from_content(content_lines: List[str], unused_file_parts:
144
161
 
145
162
  if was_block_removed:
146
163
  if ends_with_semicolon(previous_non_removed_line):
147
- updated_content_lines.append(f"{indentation_of_first_removed_line}pass\n")
164
+ updated_content_lines.append(indentation_of_first_removed_line + b'pass\n')
148
165
 
149
166
  return updated_content_lines
deadcode/cli.py CHANGED
@@ -24,12 +24,12 @@ def main(
24
24
  file_diff = fix_or_show_unused_code(unused_names, args=args)
25
25
 
26
26
  if (error_message := get_unused_names_error_message(unused_names, args=args)) is not None:
27
- return error_message + ("\n\n" + file_diff if file_diff else "")
27
+ return error_message + ('\n\n' + file_diff if file_diff else '')
28
28
 
29
29
  if not args.count and not args.quiet:
30
- print("\033[1mWell done!\033[0m ✨ 🚀 ✨")
30
+ print('\033[1mWell done!\033[0m ✨ 🚀 ✨')
31
31
  return None
32
32
 
33
33
 
34
- if __name__ == "__main__":
34
+ if __name__ == '__main__':
35
35
  main()