lapsed 3.0.0__tar.gz → 3.2.2__tar.gz

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 (363) hide show
  1. lapsed-3.2.2/.github/workflows/ci.yml +81 -0
  2. lapsed-3.2.2/.github/workflows/wheels.yml +212 -0
  3. lapsed-3.2.2/.gitignore +169 -0
  4. lapsed-3.0.0/CLAUDE.md → lapsed-3.2.2/AGENTS.md +35 -4
  5. lapsed-3.2.2/CLAUDE.md +1 -0
  6. {lapsed-3.0.0 → lapsed-3.2.2}/Cargo.lock +322 -255
  7. {lapsed-3.0.0 → lapsed-3.2.2}/Cargo.toml +9 -5
  8. {lapsed-3.0.0 → lapsed-3.2.2}/PKG-INFO +1 -1
  9. {lapsed-3.0.0 → lapsed-3.2.2}/examples/profile_stages.rs +3 -3
  10. lapsed-3.2.2/legacy-python/.github/dependabot.yml +34 -0
  11. {lapsed-3.0.0 → lapsed-3.2.2/legacy-python}/.github/workflows/check-deadcode-on-python310.yml +8 -8
  12. lapsed-3.2.2/legacy-python/.github/workflows/test.yml +53 -0
  13. lapsed-3.2.2/legacy-python/.github/workflows/vulnerability-audit.yml +73 -0
  14. {lapsed-3.0.0 → lapsed-3.2.2/legacy-python}/.gitignore +1 -0
  15. lapsed-3.2.2/legacy-python/.pre-commit-config.yaml +22 -0
  16. lapsed-3.2.2/legacy-python/.pre-commit-hooks.yaml +10 -0
  17. lapsed-3.2.2/legacy-python/.readthedocs.yaml +20 -0
  18. lapsed-3.2.2/legacy-python/LICENSE +661 -0
  19. lapsed-3.2.2/legacy-python/Makefile +149 -0
  20. lapsed-3.2.2/legacy-python/README.md +470 -0
  21. lapsed-3.2.2/legacy-python/codecov.yml +7 -0
  22. lapsed-3.2.2/legacy-python/deadcode/__init__.py +8 -0
  23. lapsed-3.2.2/legacy-python/deadcode/actions/find_python_filenames.py +34 -0
  24. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/deadcode/actions/find_unused_names.py +6 -3
  25. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/deadcode/actions/fix_or_show_unused_code.py +14 -13
  26. lapsed-3.2.2/legacy-python/deadcode/actions/get_unused_import_parts.py +207 -0
  27. lapsed-3.2.2/legacy-python/deadcode/actions/get_unused_names_error_message.py +41 -0
  28. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/deadcode/actions/merge_overlaping_file_parts.py +8 -9
  29. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/deadcode/actions/parse_abstract_syntax_tree.py +3 -2
  30. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/deadcode/actions/parse_arguments.py +46 -54
  31. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/deadcode/actions/remove_file_parts_from_content.py +33 -11
  32. lapsed-3.2.2/legacy-python/deadcode/cli.py +67 -0
  33. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/deadcode/constants.py +7 -4
  34. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/deadcode/data_types.py +3 -4
  35. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/deadcode/utils/fix_indent.py +4 -12
  36. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/deadcode/utils/flatten_lists.py +4 -4
  37. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/deadcode/utils/nested_scopes.py +11 -29
  38. lapsed-3.2.2/legacy-python/deadcode/utils/normalize_path.py +9 -0
  39. lapsed-3.2.2/legacy-python/deadcode/utils/print_safely.py +29 -0
  40. lapsed-3.2.2/legacy-python/deadcode/visitor/code_item.py +84 -0
  41. lapsed-3.2.2/legacy-python/deadcode/visitor/dead_code_visitor.py +952 -0
  42. lapsed-3.2.2/legacy-python/deadcode/visitor/ignore.py +154 -0
  43. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/deadcode/visitor/lines.py +7 -6
  44. lapsed-3.2.2/legacy-python/deadcode/visitor/module_exports.py +80 -0
  45. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/deadcode/visitor/noqa.py +3 -4
  46. lapsed-3.2.2/legacy-python/deadcode/visitor/usage_graph.py +123 -0
  47. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/deadcode/visitor/utils.py +39 -17
  48. lapsed-3.2.2/legacy-python/docs/_static/AGPLv3-license.svg +23 -0
  49. lapsed-3.2.2/legacy-python/docs/_static/custom.css +19 -0
  50. lapsed-3.2.2/legacy-python/docs/_static/deadcode-logo-readme.png +0 -0
  51. lapsed-3.2.2/legacy-python/docs/comparison.md +93 -0
  52. lapsed-3.2.2/legacy-python/docs/conf.py +20 -0
  53. lapsed-3.2.2/legacy-python/docs/contributing.md +18 -0
  54. lapsed-3.2.2/legacy-python/docs/dep.md +166 -0
  55. lapsed-3.2.2/legacy-python/docs/dep_1.md +2 -0
  56. lapsed-3.2.2/legacy-python/docs/dep_2.md +2 -0
  57. lapsed-3.2.2/legacy-python/docs/dep_3.md +2 -0
  58. lapsed-3.2.2/legacy-python/docs/dep_4.md +2 -0
  59. lapsed-3.2.2/legacy-python/docs/dep_5.md +2 -0
  60. lapsed-3.2.2/legacy-python/docs/dep_6.md +2 -0
  61. lapsed-3.2.2/legacy-python/docs/dep_7.md +2 -0
  62. lapsed-3.2.2/legacy-python/docs/django.md +478 -0
  63. lapsed-3.2.2/legacy-python/docs/fastapi.md +241 -0
  64. lapsed-3.2.2/legacy-python/docs/features.md +73 -0
  65. lapsed-3.2.2/legacy-python/docs/index.md +70 -0
  66. lapsed-3.2.2/legacy-python/docs/installation.md +6 -0
  67. lapsed-3.2.2/legacy-python/docs/known_limitations.md +6 -0
  68. lapsed-3.2.2/legacy-python/docs/open_source_experiment.md +269 -0
  69. lapsed-3.2.2/legacy-python/docs/performance.md +81 -0
  70. lapsed-3.2.2/legacy-python/docs/pre_commit.md +109 -0
  71. lapsed-3.2.2/legacy-python/docs/release_notes.md +5 -0
  72. lapsed-3.2.2/legacy-python/docs/requirements.txt +3 -0
  73. lapsed-3.2.2/legacy-python/docs/rules.md +8 -0
  74. lapsed-3.2.2/legacy-python/docs/rust.md +84 -0
  75. lapsed-3.2.2/legacy-python/docs/security.md +70 -0
  76. lapsed-3.2.2/legacy-python/docs/usage.md +13 -0
  77. lapsed-3.2.2/legacy-python/enhancement_proposals/dep_0.md +23 -0
  78. lapsed-3.2.2/legacy-python/enhancement_proposals/dep_1.md +238 -0
  79. lapsed-3.2.2/legacy-python/enhancement_proposals/dep_2.md +214 -0
  80. lapsed-3.2.2/legacy-python/enhancement_proposals/dep_3.md +176 -0
  81. lapsed-3.2.2/legacy-python/enhancement_proposals/dep_4.md +341 -0
  82. lapsed-3.2.2/legacy-python/enhancement_proposals/dep_5.md +174 -0
  83. lapsed-3.2.2/legacy-python/enhancement_proposals/dep_6.md +163 -0
  84. lapsed-3.2.2/legacy-python/enhancement_proposals/dep_7.md +337 -0
  85. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/pyproject.toml +22 -11
  86. lapsed-3.2.2/legacy-python/requirements-dev.txt +273 -0
  87. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/requirements.txt +2 -1
  88. lapsed-3.2.2/legacy-python/tests/actions/test_find_python_filenames.py +165 -0
  89. lapsed-3.2.2/legacy-python/tests/actions/test_get_unused_import_parts.py +229 -0
  90. lapsed-3.2.2/legacy-python/tests/actions/test_merge_overlaping_file_parts.py +86 -0
  91. lapsed-3.2.2/legacy-python/tests/actions/test_remove_file_parts_from_content.py +73 -0
  92. lapsed-3.2.2/legacy-python/tests/cli/test_cli_exit_status.py +163 -0
  93. lapsed-3.2.2/legacy-python/tests/cli/test_cli_module_entry_point.py +22 -0
  94. lapsed-3.2.2/legacy-python/tests/cli/test_cli_output_encoding.py +117 -0
  95. lapsed-3.2.2/legacy-python/tests/cli/test_deadcode.py +69 -0
  96. lapsed-3.2.2/legacy-python/tests/cli/test_output.py +138 -0
  97. lapsed-3.2.2/legacy-python/tests/cli/test_verbose_output_encoding.py +97 -0
  98. lapsed-3.2.2/legacy-python/tests/cli_args/test_argument_routes.py +117 -0
  99. lapsed-3.2.2/legacy-python/tests/cli_args/test_count.py +79 -0
  100. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/tests/cli_args/test_dry.py +131 -121
  101. lapsed-3.2.2/legacy-python/tests/cli_args/test_exclude.py +88 -0
  102. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/tests/cli_args/test_fix.py +291 -208
  103. lapsed-3.2.2/legacy-python/tests/cli_args/test_ignore_bodies_if_decorated_with.py +112 -0
  104. lapsed-3.2.2/legacy-python/tests/cli_args/test_ignore_bodies_if_inherits_from.py +158 -0
  105. lapsed-3.2.2/legacy-python/tests/cli_args/test_ignore_bodies_of.py +141 -0
  106. lapsed-3.2.2/legacy-python/tests/cli_args/test_ignore_definitions.py +282 -0
  107. lapsed-3.2.2/legacy-python/tests/cli_args/test_ignore_definitions_if_decorated_with.py +155 -0
  108. lapsed-3.2.2/legacy-python/tests/cli_args/test_ignore_definitions_if_inherits_from.py +291 -0
  109. lapsed-3.2.2/legacy-python/tests/cli_args/test_ignore_names.py +90 -0
  110. lapsed-3.2.2/legacy-python/tests/cli_args/test_ignore_names_if_decorated_with.py +201 -0
  111. lapsed-3.2.2/legacy-python/tests/cli_args/test_ignore_names_if_inherits_from.py +269 -0
  112. lapsed-3.2.2/legacy-python/tests/cli_args/test_ignore_names_in_files.py +99 -0
  113. lapsed-3.2.2/legacy-python/tests/cli_args/test_ignore_option_combinations.py +114 -0
  114. lapsed-3.2.2/legacy-python/tests/cli_args/test_ignore_rules.py +106 -0
  115. lapsed-3.2.2/legacy-python/tests/cli_args/test_no_color.py +37 -0
  116. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/tests/cli_args/test_only.py +64 -63
  117. lapsed-3.2.2/legacy-python/tests/cli_args/test_parsing.py +263 -0
  118. lapsed-3.2.2/legacy-python/tests/cli_args/test_pyproject_boolean_options.py +116 -0
  119. lapsed-3.2.2/legacy-python/tests/cli_args/test_pyproject_list_options.py +121 -0
  120. lapsed-3.2.2/legacy-python/tests/cli_args/test_quiet.py +82 -0
  121. lapsed-3.2.2/legacy-python/tests/cli_args/test_verbose.py +75 -0
  122. lapsed-3.2.2/legacy-python/tests/cli_args/test_version.py +34 -0
  123. lapsed-3.2.2/legacy-python/tests/code_item/test_code_item.py +102 -0
  124. lapsed-3.2.2/legacy-python/tests/configuration/test_decorator_pyproject_configuration.py +114 -0
  125. lapsed-3.2.2/legacy-python/tests/conftest.py +108 -0
  126. lapsed-3.2.2/legacy-python/tests/documented_examples/test_django.py +654 -0
  127. lapsed-3.2.2/legacy-python/tests/documented_examples/test_documented_features.py +180 -0
  128. lapsed-3.2.2/legacy-python/tests/documented_examples/test_documented_options.py +82 -0
  129. lapsed-3.2.2/legacy-python/tests/documented_examples/test_documented_rules.py +91 -0
  130. lapsed-3.2.2/legacy-python/tests/documented_examples/test_fastapi.py +120 -0
  131. lapsed-3.2.2/legacy-python/tests/documented_examples/test_fastapi_dependency_injection.py +74 -0
  132. lapsed-3.2.2/legacy-python/tests/documented_examples/test_fastapi_documentation.py +70 -0
  133. lapsed-3.2.2/legacy-python/tests/documented_examples/test_pre_commit_hook_configuration.py +66 -0
  134. lapsed-3.2.2/legacy-python/tests/documented_examples/test_readme_coverage_badge.py +41 -0
  135. lapsed-3.2.2/legacy-python/tests/files/classes.py +15 -0
  136. lapsed-3.2.2/legacy-python/tests/files/django/admin.py +20 -0
  137. lapsed-3.2.2/legacy-python/tests/files/django/api.py +46 -0
  138. lapsed-3.2.2/legacy-python/tests/files/django/apps.py +9 -0
  139. lapsed-3.2.2/legacy-python/tests/files/django/forms.py +16 -0
  140. lapsed-3.2.2/legacy-python/tests/files/django/import_forms.py +34 -0
  141. lapsed-3.2.2/legacy-python/tests/files/django/management/commands/import_data.py +16 -0
  142. lapsed-3.2.2/legacy-python/tests/files/django/managers.py +14 -0
  143. lapsed-3.2.2/legacy-python/tests/files/django/middleware.py +29 -0
  144. lapsed-3.2.2/legacy-python/tests/files/django/migrations/0001_initial.py +18 -0
  145. lapsed-3.2.2/legacy-python/tests/files/django/models.py +36 -0
  146. lapsed-3.2.2/legacy-python/tests/files/django/settings.py +38 -0
  147. lapsed-3.2.2/legacy-python/tests/files/django/signals.py +20 -0
  148. lapsed-3.2.2/legacy-python/tests/files/django/templatetags/blog_tags.py +17 -0
  149. lapsed-3.2.2/legacy-python/tests/files/django/tests.py +27 -0
  150. lapsed-3.2.2/legacy-python/tests/files/django/urls.py +21 -0
  151. lapsed-3.2.2/legacy-python/tests/files/django/views.py +54 -0
  152. lapsed-3.2.2/legacy-python/tests/files/fastapi/dependencies.py +9 -0
  153. lapsed-3.2.2/legacy-python/tests/files/fastapi/main.py +37 -0
  154. lapsed-3.2.2/legacy-python/tests/files/fastapi/models.py +10 -0
  155. lapsed-3.2.2/legacy-python/tests/files/fastapi/routes/users.py +20 -0
  156. lapsed-3.2.2/legacy-python/tests/files/fastapi_dependency_injection/dependencies.py +49 -0
  157. lapsed-3.2.2/legacy-python/tests/files/fastapi_dependency_injection/main.py +116 -0
  158. lapsed-3.2.2/legacy-python/tests/files/fastapi_dependency_injection/models.py +5 -0
  159. lapsed-3.2.2/legacy-python/tests/files/fastapi_dependency_injection/security.py +26 -0
  160. lapsed-3.2.2/legacy-python/tests/files/fastapi_features/background.py +2 -0
  161. lapsed-3.2.2/legacy-python/tests/files/fastapi_features/errors.py +7 -0
  162. lapsed-3.2.2/legacy-python/tests/files/fastapi_features/main.py +103 -0
  163. lapsed-3.2.2/legacy-python/tests/files/fastapi_features/middleware.py +11 -0
  164. lapsed-3.2.2/legacy-python/tests/files/fastapi_features/models.py +36 -0
  165. lapsed-3.2.2/legacy-python/tests/files/fastapi_features/routes/items.py +66 -0
  166. lapsed-3.2.2/legacy-python/tests/files/fastapi_features/security.py +21 -0
  167. lapsed-3.2.2/legacy-python/tests/fix/test_assign.py +487 -0
  168. lapsed-3.2.2/legacy-python/tests/fix/test_attribute.py +46 -0
  169. lapsed-3.2.2/legacy-python/tests/fix/test_cascading_dead_code.py +122 -0
  170. lapsed-3.2.2/legacy-python/tests/fix/test_class_def.py +128 -0
  171. lapsed-3.2.2/legacy-python/tests/fix/test_commented_out_code.py +68 -0
  172. lapsed-3.2.2/legacy-python/tests/fix/test_empty_files.py +37 -0
  173. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/tests/fix/test_method_def.py +29 -24
  174. lapsed-3.2.2/legacy-python/tests/fix/test_property.py +38 -0
  175. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/tests/fix/test_scope.py +130 -80
  176. lapsed-3.2.2/legacy-python/tests/fix/test_unreachable_code.py +141 -0
  177. lapsed-3.2.2/legacy-python/tests/fix/test_unused_imports.py +732 -0
  178. lapsed-3.2.2/legacy-python/tests/nested_scope/test_nested_scope.py +223 -0
  179. lapsed-3.2.2/legacy-python/tests/noqa/test_noqa_comments.py +638 -0
  180. lapsed-3.2.2/legacy-python/tests/regression/test_cascading_dead_code.py +415 -0
  181. lapsed-3.2.2/legacy-python/tests/regression/test_name_shadowing.py +355 -0
  182. lapsed-3.2.2/legacy-python/tests/regression/test_python314_attribute_error.py +29 -0
  183. lapsed-3.2.2/legacy-python/tests/utils/test_add_colors_to_diff.py +34 -0
  184. lapsed-3.2.2/legacy-python/tests/utils/test_fix_indent.py +34 -0
  185. lapsed-3.2.2/legacy-python/tests/utils/test_normalize_path.py +27 -0
  186. lapsed-3.2.2/legacy-python/tests/utils/test_print_ast.py +16 -0
  187. lapsed-3.2.2/legacy-python/tests/utils/test_print_safely.py +145 -0
  188. lapsed-3.2.2/legacy-python/tests/visitor/test_accurate_usage_detection.py +54 -0
  189. lapsed-3.2.2/legacy-python/tests/visitor/test_commented_out_code.py +113 -0
  190. lapsed-3.2.2/legacy-python/tests/visitor/test_decorator_without_id_attribute.py +47 -0
  191. lapsed-3.2.2/legacy-python/tests/visitor/test_django_lifecycle_methods.py +207 -0
  192. lapsed-3.2.2/legacy-python/tests/visitor/test_ignore.py +28 -0
  193. lapsed-3.2.2/legacy-python/tests/visitor/test_ignore_interface_decorators.py +212 -0
  194. lapsed-3.2.2/legacy-python/tests/visitor/test_imports.py +379 -0
  195. lapsed-3.2.2/legacy-python/tests/visitor/test_line_number_detection.py +124 -0
  196. lapsed-3.2.2/legacy-python/tests/visitor/test_middleware_registration.py +122 -0
  197. lapsed-3.2.2/legacy-python/tests/visitor/test_name_usage_and_unreachable_detection.py +149 -0
  198. lapsed-3.2.2/legacy-python/tests/visitor/test_qualified_name_resolution.py +151 -0
  199. lapsed-3.2.2/legacy-python/tests/visitor/test_unittest_lifecycle_methods.py +107 -0
  200. lapsed-3.2.2/legacy-python/tests/visitor/test_utils.py +72 -0
  201. {lapsed-3.0.0/legacy-python/tests → lapsed-3.2.2/legacy-python/tests/visitor}/test_variable_parsing_from_ast_dump.py +0 -6
  202. lapsed-3.2.2/legacy-python/tests/visitor/test_wildcard_imports.py +466 -0
  203. {lapsed-3.0.0 → lapsed-3.2.2}/pyproject.toml +1 -1
  204. lapsed-3.2.2/scripts/check.py +214 -0
  205. lapsed-3.2.2/scripts/parity.py +221 -0
  206. {lapsed-3.0.0 → lapsed-3.2.2}/src/actions/find_python_filenames.rs +71 -9
  207. {lapsed-3.0.0 → lapsed-3.2.2}/src/actions/fix_or_show_unused_code.rs +52 -22
  208. lapsed-3.2.2/src/actions/get_unused_import_parts.rs +342 -0
  209. lapsed-3.2.2/src/actions/parse_abstract_syntax_tree.rs +103 -0
  210. {lapsed-3.0.0 → lapsed-3.2.2}/src/actions/parse_arguments.rs +76 -4
  211. {lapsed-3.0.0 → lapsed-3.2.2}/src/actions/parse_tach_config.rs +89 -7
  212. lapsed-3.2.2/src/actions/remove_file_parts_from_content.rs +502 -0
  213. {lapsed-3.0.0 → lapsed-3.2.2}/src/cli.rs +151 -8
  214. {lapsed-3.0.0 → lapsed-3.2.2}/src/constants.rs +5 -2
  215. {lapsed-3.0.0 → lapsed-3.2.2}/src/data_types.rs +9 -5
  216. {lapsed-3.0.0 → lapsed-3.2.2}/src/lib.rs +2 -0
  217. {lapsed-3.0.0 → lapsed-3.2.2}/src/utils/fix_indent.rs +1 -1
  218. {lapsed-3.0.0 → lapsed-3.2.2}/src/utils/line_index.rs +5 -5
  219. lapsed-3.2.2/src/visitor/dead_code_visitor.rs +2194 -0
  220. {lapsed-3.0.0 → lapsed-3.2.2}/src/visitor/ignore.rs +67 -5
  221. {lapsed-3.0.0 → lapsed-3.2.2}/src/visitor/utils.rs +7 -14
  222. lapsed-3.2.2/tests/attrs_field_hooks.rs +90 -0
  223. {lapsed-3.0.0 → lapsed-3.2.2}/tests/deadcode_integration.rs +8 -3
  224. {lapsed-3.0.0 → lapsed-3.2.2}/tests/exit_code.rs +50 -0
  225. lapsed-3.2.2/tests/files/functions.py +21 -0
  226. lapsed-3.2.2/tests/files/subdir/another_subdir/__init__.py +1 -0
  227. lapsed-3.2.2/tests/files/subdir/one_more_file.py +2 -0
  228. lapsed-3.2.2/tests/files/variables.py +8 -0
  229. lapsed-3.2.2/tests/fix_special_cases.rs +349 -0
  230. {lapsed-3.0.0 → lapsed-3.2.2}/tests/ignore_flags_cli.rs +1 -1
  231. {lapsed-3.0.0 → lapsed-3.2.2}/tests/imports_and_output.rs +4 -1
  232. lapsed-3.2.2/tests/modern_python_syntax.rs +158 -0
  233. {lapsed-3.0.0 → lapsed-3.2.2}/tests/noqa_comments.rs +12 -0
  234. lapsed-3.2.2/tests/parity/cases/absimport/main.py +2 -0
  235. lapsed-3.2.2/tests/parity/cases/absimport/pkg/a.py +4 -0
  236. lapsed-3.2.2/tests/parity/cases/abstract/m.py +10 -0
  237. lapsed-3.2.2/tests/parity/cases/cascade/m.py +5 -0
  238. lapsed-3.2.2/tests/parity/cases/dc06/m.py +6 -0
  239. lapsed-3.2.2/tests/parity/cases/dc09/m.py +8 -0
  240. lapsed-3.2.2/tests/parity/cases/dc09b/m.py +15 -0
  241. lapsed-3.2.2/tests/parity/cases/dc12/m.py +6 -0
  242. lapsed-3.2.2/tests/parity/cases/dc13/m.py +4 -0
  243. lapsed-3.2.2/tests/parity/cases/django/m.py +21 -0
  244. lapsed-3.2.2/tests/parity/cases/django_mw/proj/middleware.py +7 -0
  245. lapsed-3.2.2/tests/parity/cases/django_mw/proj/settings.py +1 -0
  246. lapsed-3.2.2/tests/parity/cases/dotted_base/m.py +10 -0
  247. lapsed-3.2.2/tests/parity/cases/fastapi/m.py +14 -0
  248. lapsed-3.2.2/tests/parity/cases/fix_edge_cases/m.py +33 -0
  249. lapsed-3.2.2/tests/parity/cases/imports_fix/m.py +9 -0
  250. lapsed-3.2.2/tests/parity/cases/multiline_assign/m.py +6 -0
  251. lapsed-3.2.2/tests/parity/cases/noqa_decorated/m.py +7 -0
  252. lapsed-3.2.2/tests/parity/cases/pyproject_options/m.py +2 -0
  253. lapsed-3.2.2/tests/parity/cases/pyproject_options/pyproject.toml +4 -0
  254. lapsed-3.2.2/tests/parity/cases/quoted/m.py +6 -0
  255. lapsed-3.2.2/tests/parity/cases/samename/a.py +2 -0
  256. lapsed-3.2.2/tests/parity/cases/samename/b.py +2 -0
  257. lapsed-3.2.2/tests/parity/cases/samename/c.py +2 -0
  258. lapsed-3.2.2/tests/parity/cases/shadowing/m.py +7 -0
  259. lapsed-3.2.2/tests/parity/cases/typecomment/m.py +4 -0
  260. lapsed-3.2.2/tests/parity/cases/unicode/m.py +2 -0
  261. lapsed-3.2.2/tests/parity/cases/wildcard/m.py +6 -0
  262. lapsed-3.2.2/tests/parity/known_differences.txt +27 -0
  263. {lapsed-3.0.0 → lapsed-3.2.2}/tests/pytest_and_typing.rs +85 -0
  264. {lapsed-3.0.0 → lapsed-3.2.2}/tests/scope_tracking.rs +36 -0
  265. {lapsed-3.0.0 → lapsed-3.2.2}/tests/tach_config_cli.rs +153 -0
  266. lapsed-3.2.2/tests/version_consistency.rs +94 -0
  267. lapsed-3.0.0/.github/workflows/wheels.yml +0 -113
  268. lapsed-3.0.0/RUST_PORT_PLAN.md +0 -284
  269. lapsed-3.0.0/example.txt +0 -6
  270. lapsed-3.0.0/legacy-python/Makefile +0 -53
  271. lapsed-3.0.0/legacy-python/deadcode/__init__.py +0 -10
  272. lapsed-3.0.0/legacy-python/deadcode/actions/find_python_filenames.py +0 -64
  273. lapsed-3.0.0/legacy-python/deadcode/actions/get_unused_names_error_message.py +0 -37
  274. lapsed-3.0.0/legacy-python/deadcode/actions/parse_tach_config.py +0 -257
  275. lapsed-3.0.0/legacy-python/deadcode/cli.py +0 -57
  276. lapsed-3.0.0/legacy-python/deadcode/todo +0 -163
  277. lapsed-3.0.0/legacy-python/deadcode/utils/base_test_case.py +0 -88
  278. lapsed-3.0.0/legacy-python/deadcode/visitor/code_item.py +0 -142
  279. lapsed-3.0.0/legacy-python/deadcode/visitor/dead_code_visitor.py +0 -594
  280. lapsed-3.0.0/legacy-python/deadcode/visitor/ignore.py +0 -176
  281. lapsed-3.0.0/legacy-python/requirements-dev.txt +0 -185
  282. lapsed-3.0.0/legacy-python/tests/actions/test_find_python_filenames.py +0 -36
  283. lapsed-3.0.0/legacy-python/tests/actions/test_merge_overlaping_file_parts.py +0 -62
  284. lapsed-3.0.0/legacy-python/tests/cli_args/test_exclude.py +0 -24
  285. lapsed-3.0.0/legacy-python/tests/cli_args/test_ignore_bodies_if_inherits_from.py +0 -46
  286. lapsed-3.0.0/legacy-python/tests/cli_args/test_ignore_class_attributes.py +0 -74
  287. lapsed-3.0.0/legacy-python/tests/cli_args/test_ignore_definitions.py +0 -106
  288. lapsed-3.0.0/legacy-python/tests/cli_args/test_ignore_definitions_if_inherits_from.py +0 -125
  289. lapsed-3.0.0/legacy-python/tests/cli_args/test_ignore_names.py +0 -79
  290. lapsed-3.0.0/legacy-python/tests/cli_args/test_ignore_non_self_attributes.py +0 -52
  291. lapsed-3.0.0/legacy-python/tests/cli_args/test_parsing.py +0 -117
  292. lapsed-3.0.0/legacy-python/tests/cli_args/test_quiet.py +0 -0
  293. lapsed-3.0.0/legacy-python/tests/cli_args/test_tach_config.py +0 -366
  294. lapsed-3.0.0/legacy-python/tests/cli_args/test_verbose.py +0 -0
  295. lapsed-3.0.0/legacy-python/tests/cli_args/test_version.py +0 -41
  296. lapsed-3.0.0/legacy-python/tests/code_item/test_code_item.py +0 -16
  297. lapsed-3.0.0/legacy-python/tests/fix/test_assign.py +0 -92
  298. lapsed-3.0.0/legacy-python/tests/fix/test_class_def.py +0 -117
  299. lapsed-3.0.0/legacy-python/tests/fix/test_empty_files.py +0 -36
  300. lapsed-3.0.0/legacy-python/tests/fix/test_unreachable_code.py +0 -100
  301. lapsed-3.0.0/legacy-python/tests/fix/test_unused_imports.py +0 -59
  302. lapsed-3.0.0/legacy-python/tests/nested_scope/test_nested_scope.py +0 -180
  303. lapsed-3.0.0/legacy-python/tests/noqa/test_noqa_comments.py +0 -400
  304. lapsed-3.0.0/legacy-python/tests/tach/test_parse_tach_config.py +0 -260
  305. lapsed-3.0.0/legacy-python/tests/test_accurate_usage_detection.py +0 -49
  306. lapsed-3.0.0/legacy-python/tests/test_deadcode.py +0 -68
  307. lapsed-3.0.0/legacy-python/tests/test_exit_code.py +0 -82
  308. lapsed-3.0.0/legacy-python/tests/test_imports.py +0 -101
  309. lapsed-3.0.0/legacy-python/tests/test_line_number_detection.py +0 -97
  310. lapsed-3.0.0/legacy-python/tests/test_output.py +0 -137
  311. lapsed-3.0.0/legacy-python/tests/test_pytest_fixtures.py +0 -172
  312. lapsed-3.0.0/legacy-python/tests/test_pytest_hooks.py +0 -47
  313. lapsed-3.0.0/legacy-python/tests/test_typing_override.py +0 -75
  314. lapsed-3.0.0/legacy-python/tests/utils/test_add_colors_to_diff.py +0 -38
  315. lapsed-3.0.0/legacy-python/tests/utils/test_fix_indent.py +0 -10
  316. lapsed-3.0.0/legacy-python/tests/visitor/test_utils.py +0 -35
  317. lapsed-3.0.0/profiling_comparison.md +0 -74
  318. lapsed-3.0.0/profiling_report.md +0 -339
  319. lapsed-3.0.0/profiling_report_after.md +0 -329
  320. lapsed-3.0.0/profiling_report_round2.md +0 -159
  321. lapsed-3.0.0/profiling_round2_raw.txt +0 -267
  322. lapsed-3.0.0/profiling_rust_vs_python.md +0 -111
  323. lapsed-3.0.0/src/actions/remove_file_parts_from_content.rs +0 -206
  324. lapsed-3.0.0/src/visitor/dead_code_visitor.rs +0 -1432
  325. lapsed-3.0.0/tests/fix_special_cases.rs +0 -109
  326. {lapsed-3.0.0 → lapsed-3.2.2}/.pre-commit-hooks.yaml +0 -0
  327. {lapsed-3.0.0 → lapsed-3.2.2}/LICENSE +0 -0
  328. {lapsed-3.0.0 → lapsed-3.2.2}/README.md +0 -0
  329. {lapsed-3.0.0 → lapsed-3.2.2}/docs/_static/AGPLv3-license.svg +0 -0
  330. {lapsed-3.0.0 → lapsed-3.2.2}/docs/_static/deadcode-logo-readme.png +0 -0
  331. {lapsed-3.0.0 → lapsed-3.2.2}/enhancement_proposals/dep_0.md +0 -0
  332. {lapsed-3.0.0 → lapsed-3.2.2}/enhancement_proposals/dep_1.md +0 -0
  333. {lapsed-3.0.0 → lapsed-3.2.2}/enhancement_proposals/dep_2.md +0 -0
  334. {lapsed-3.0.0 → lapsed-3.2.2}/enhancement_proposals/dep_3.md +0 -0
  335. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/deadcode/actions/__init__.py +0 -0
  336. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/deadcode/utils/__init__.py +0 -0
  337. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/deadcode/utils/add_colors_to_diff.py +0 -0
  338. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/deadcode/utils/print_ast.py +0 -0
  339. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/deadcode/visitor/__init__.py +0 -0
  340. {lapsed-3.0.0 → lapsed-3.2.2}/legacy-python/tests/cli_args/__init__.py +0 -0
  341. {lapsed-3.0.0 → lapsed-3.2.2/legacy-python}/tests/files/functions.py +0 -0
  342. {lapsed-3.0.0 → lapsed-3.2.2/legacy-python}/tests/files/subdir/another_subdir/__init__.py +0 -0
  343. {lapsed-3.0.0 → lapsed-3.2.2/legacy-python}/tests/files/subdir/one_more_file.py +0 -0
  344. {lapsed-3.0.0 → lapsed-3.2.2/legacy-python}/tests/files/variables.py +0 -0
  345. {lapsed-3.0.0/legacy-python/tests/tach → lapsed-3.2.2/legacy-python/tests/fix}/__init__.py +0 -0
  346. {lapsed-3.0.0/legacy-python/tests/utils → lapsed-3.2.2/legacy-python/tests/regression}/__init__.py +0 -0
  347. /lapsed-3.0.0/legacy-python/tests/cli_args/test_count.py → /lapsed-3.2.2/legacy-python/tests/utils/__init__.py +0 -0
  348. /lapsed-3.0.0/legacy-python/tests/cli_args/test_ignore_names_in_files.py → /lapsed-3.2.2/legacy-python/tests/visitor/__init__.py +0 -0
  349. {lapsed-3.0.0 → lapsed-3.2.2}/src/actions/get_unused_names_error_message.rs +0 -0
  350. {lapsed-3.0.0 → lapsed-3.2.2}/src/actions/merge_overlapping_file_parts.rs +0 -0
  351. {lapsed-3.0.0 → lapsed-3.2.2}/src/main.rs +0 -0
  352. {lapsed-3.0.0 → lapsed-3.2.2}/src/utils/add_colors_to_diff.rs +0 -0
  353. {lapsed-3.0.0 → lapsed-3.2.2}/src/utils/fnmatch.rs +0 -0
  354. {lapsed-3.0.0 → lapsed-3.2.2}/src/utils/nested_scopes.rs +0 -0
  355. {lapsed-3.0.0 → lapsed-3.2.2}/src/utils/path_utils.rs +0 -0
  356. {lapsed-3.0.0 → lapsed-3.2.2}/src/visitor/code_item.rs +0 -0
  357. {lapsed-3.0.0 → lapsed-3.2.2}/src/visitor/noqa.rs +0 -0
  358. {lapsed-3.0.0 → lapsed-3.2.2}/tests/aspirational_unimplemented.rs +0 -0
  359. {lapsed-3.0.0 → lapsed-3.2.2}/tests/common/mod.rs +0 -0
  360. {lapsed-3.0.0 → lapsed-3.2.2}/tests/files/classes.py +0 -0
  361. {lapsed-3.0.0 → lapsed-3.2.2}/tests/fix_cli_option.rs +0 -0
  362. {lapsed-3.0.0 → lapsed-3.2.2}/tests/line_number_detection.rs +0 -0
  363. /lapsed-3.0.0/legacy-python/tests/cli_args/test_no_color.py → /lapsed-3.2.2/tests/parity/cases/absimport/pkg/__init__.py +0 -0
@@ -0,0 +1,81 @@
1
+ name: CI
2
+
3
+ # Runs on every pull request regardless of base branch, and on v* tags.
4
+ #
5
+ # Deliberately NOT restricted to `branches: [main]` the way the older workflows
6
+ # are: this project develops through staging/test_release/feature branches, and
7
+ # a base-branch filter means a PR into anything but main gets no CI at all.
8
+ on:
9
+ pull_request:
10
+ push:
11
+ tags: ["v*"]
12
+ # Manual runs, useful for checking a branch before opening the PR.
13
+ workflow_dispatch:
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ # A newer push to the same PR supersedes the old run; tag builds are never
19
+ # cancelled, since those gate a release.
20
+ concurrency:
21
+ group: ci-${{ github.workflow }}-${{ github.ref }}
22
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
23
+
24
+ jobs:
25
+ # Version-independent checks: the Rust toolchain, the Python linters (which
26
+ # analyse source rather than run it), and parity, which runs the Rust CLI and
27
+ # legacy-python side by side (see scripts/parity.py).
28
+ static:
29
+ name: ${{ matrix.check }}
30
+ runs-on: ubuntu-latest
31
+ strategy:
32
+ # Report every failing check in one run, rather than hiding the rest
33
+ # behind whichever fails first.
34
+ fail-fast: false
35
+ matrix:
36
+ check: [fmt, clippy, test, ruff, ruff-format, mypy, parity]
37
+ steps:
38
+ - uses: actions/checkout@v4
39
+
40
+ - name: Install Rust
41
+ uses: dtolnay/rust-toolchain@stable
42
+ with:
43
+ # Only the checks that need them, so the Python jobs stay lean.
44
+ components: ${{ (matrix.check == 'fmt' && 'rustfmt') || (matrix.check == 'clippy' && 'clippy') || '' }}
45
+
46
+ - name: Cache cargo
47
+ uses: Swatinem/rust-cache@v2
48
+ with:
49
+ key: ${{ matrix.check }}
50
+
51
+ - name: Install uv
52
+ uses: astral-sh/setup-uv@v5
53
+ with:
54
+ enable-cache: true
55
+
56
+ # The exact command a developer runs locally.
57
+ - run: python scripts/check.py ${{ matrix.check }}
58
+
59
+ # The legacy Python suite, once per supported interpreter.
60
+ #
61
+ # Keep this list in sync with PYTHON_VERSIONS in scripts/check.py and the
62
+ # classifiers in legacy-python/pyproject.toml. 3.14 matters most here: it
63
+ # removed ast.Str/Num/Bytes/NameConstant/Ellipsis, which the visitor used.
64
+ pytest:
65
+ name: pytest (Python ${{ matrix.python }})
66
+ runs-on: ubuntu-latest
67
+ strategy:
68
+ fail-fast: false
69
+ matrix:
70
+ python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
71
+ steps:
72
+ - uses: actions/checkout@v4
73
+
74
+ - name: Install uv
75
+ uses: astral-sh/setup-uv@v5
76
+ with:
77
+ enable-cache: true
78
+
79
+ # uv fetches the interpreter itself, so no setup-python step is needed
80
+ # and the matrix cannot drift from what the runner image happens to ship.
81
+ - run: python scripts/check.py pytest --python ${{ matrix.python }}
@@ -0,0 +1,212 @@
1
+ name: Build Rust wheels
2
+
3
+ # Wheels are the release artifact, so v* tags must build them -- previously
4
+ # tags triggered nothing at all. `pull_request` is unfiltered for the same
5
+ # reason as in ci.yml: a base-branch filter means PRs into staging or
6
+ # test_release get no wheel build.
7
+ on:
8
+ pull_request:
9
+ push:
10
+ branches: [ "main" ]
11
+ tags: [ "v*" ]
12
+ workflow_dispatch:
13
+
14
+ permissions:
15
+ contents: read
16
+
17
+ jobs:
18
+ test:
19
+ name: cargo test (${{ matrix.os }})
20
+ runs-on: ${{ matrix.os }}
21
+ strategy:
22
+ fail-fast: false
23
+ matrix:
24
+ os: [ubuntu-latest, windows-latest, macos-latest]
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+ - uses: dtolnay/rust-toolchain@stable
28
+ - run: cargo test --all-features
29
+
30
+ linux:
31
+ name: wheel (linux ${{ matrix.target }})
32
+ needs: test
33
+ runs-on: ubuntu-latest
34
+ strategy:
35
+ fail-fast: false
36
+ matrix:
37
+ target: [x86_64, aarch64]
38
+ steps:
39
+ - uses: actions/checkout@v4
40
+ - name: Build manylinux wheel
41
+ uses: PyO3/maturin-action@v1
42
+ with:
43
+ target: ${{ matrix.target }}
44
+ args: --release --out dist
45
+ manylinux: auto
46
+ - uses: actions/upload-artifact@v4
47
+ with:
48
+ name: wheels-linux-${{ matrix.target }}
49
+ path: dist/*.whl
50
+
51
+ windows:
52
+ name: wheel (windows ${{ matrix.target }})
53
+ needs: test
54
+ runs-on: windows-latest
55
+ strategy:
56
+ fail-fast: false
57
+ matrix:
58
+ target: [x64, x86]
59
+ steps:
60
+ - uses: actions/checkout@v4
61
+ - uses: actions/setup-python@v5
62
+ with:
63
+ python-version: "3.12"
64
+ architecture: ${{ matrix.target }}
65
+ - name: Build wheel
66
+ uses: PyO3/maturin-action@v1
67
+ with:
68
+ target: ${{ matrix.target == 'x64' && 'x86_64-pc-windows-msvc' || 'i686-pc-windows-msvc' }}
69
+ args: --release --out dist
70
+ - uses: actions/upload-artifact@v4
71
+ with:
72
+ name: wheels-windows-${{ matrix.target }}
73
+ path: dist/*.whl
74
+
75
+ macos:
76
+ name: wheel (macos ${{ matrix.target }})
77
+ needs: test
78
+ runs-on: macos-latest
79
+ strategy:
80
+ fail-fast: false
81
+ matrix:
82
+ target: [x86_64, aarch64]
83
+ steps:
84
+ - uses: actions/checkout@v4
85
+ - name: Build wheel
86
+ uses: PyO3/maturin-action@v1
87
+ with:
88
+ target: ${{ matrix.target }}
89
+ args: --release --out dist
90
+ - uses: actions/upload-artifact@v4
91
+ with:
92
+ name: wheels-macos-${{ matrix.target }}
93
+ path: dist/*.whl
94
+
95
+ sdist:
96
+ name: source distribution
97
+ needs: test
98
+ runs-on: ubuntu-latest
99
+ steps:
100
+ - uses: actions/checkout@v4
101
+ - uses: PyO3/maturin-action@v1
102
+ with:
103
+ command: sdist
104
+ args: --out dist
105
+ - uses: actions/upload-artifact@v4
106
+ with:
107
+ name: sdist
108
+ path: dist/*.tar.gz
109
+
110
+ # Every wheel installs and runs on its target platform.
111
+ smoke-test:
112
+ name: install & smoke test (${{ matrix.os }})
113
+ needs: [linux, windows, macos]
114
+ runs-on: ${{ matrix.os }}
115
+ strategy:
116
+ fail-fast: false
117
+ # Runner and artifact are paired explicitly rather than derived from the
118
+ # OS name. A wheel only installs on a matching architecture, and the
119
+ # previous nested-ternary form hardcoded macos-x86_64 -- which broke once
120
+ # `macos-latest` became Apple Silicon (macos-26-arm64), since the x86_64
121
+ # wheel is not installable there. Pairing them here means adding a
122
+ # platform is one obvious edit instead of an easily-missed branch.
123
+ #
124
+ # Not every built wheel has a runner to test on: linux-aarch64,
125
+ # windows-x86, and (as of GitHub retiring free Intel macOS hosting
126
+ # entirely -- every x64 macOS label is now a paid large-runner, e.g.
127
+ # macos-15-intel/macos-14-large -- macos-x86_64) are shipped untested.
128
+ # macos-13 used to cover the x86_64 wheel, but that label has no runner
129
+ # left to schedule it on: the job just queues forever and gets
130
+ # auto-cancelled by GitHub after 24h, which is what happened here.
131
+ matrix:
132
+ include:
133
+ - os: ubuntu-latest
134
+ artifact: wheels-linux-x86_64
135
+ - os: windows-latest
136
+ artifact: wheels-windows-x64
137
+ # macos-latest tracks whatever Apple Silicon image GitHub currently
138
+ # calls "latest", so it catches drift early.
139
+ - os: macos-latest
140
+ artifact: wheels-macos-aarch64
141
+ # macos-15 is a hard-pinned Apple Silicon version (not a moving
142
+ # "-latest" symlink), so this job stays reproducible even if/when
143
+ # "latest" moves again.
144
+ - os: macos-15
145
+ artifact: wheels-macos-aarch64
146
+ steps:
147
+ - uses: actions/checkout@v4
148
+ - uses: actions/setup-python@v5
149
+ with:
150
+ python-version: "3.12"
151
+ - name: Download this OS's wheel
152
+ uses: actions/download-artifact@v4
153
+ with:
154
+ pattern: ${{ matrix.artifact }}
155
+ path: dist
156
+ merge-multiple: true
157
+ # Fail loudly if the download produced nothing, rather than letting the
158
+ # install step report a confusing "no matching distribution".
159
+ - name: Verify a wheel was downloaded
160
+ shell: bash
161
+ run: |
162
+ ls -l dist
163
+ if [ "$(ls dist/*.whl 2>/dev/null | wc -l)" -eq 0 ]; then
164
+ echo "::error::no .whl in dist for ${{ matrix.artifact }}"
165
+ exit 1
166
+ fi
167
+ # The distribution is `lapsed`; the command it installs is `deadcode`.
168
+ # `--no-index` matters: this previously asked for `deadcode`, which does
169
+ # not match the built `lapsed-*.whl`, so pip fell through to PyPI and
170
+ # smoke-tested an unrelated package instead of this build. Forbidding the
171
+ # index makes that failure loud rather than silent.
172
+ - run: pip install --no-index --find-links dist lapsed
173
+ - run: deadcode --version
174
+
175
+ # Pushing a `v*` tag publishes to PyPI once every wheel built and smoke-tested.
176
+ # Uses PyPI trusted publishing (OIDC), so there is no token in the repository:
177
+ # register this workflow as a trusted publisher for `lapsed` on PyPI
178
+ # (owner ColinKennedy, repo deadcode, workflow wheels.yml, environment pypi).
179
+ publish:
180
+ name: publish to PyPI
181
+ if: startsWith(github.ref, 'refs/tags/v')
182
+ needs: [sdist, smoke-test]
183
+ runs-on: ubuntu-latest
184
+ environment:
185
+ name: pypi
186
+ url: https://pypi.org/project/lapsed/
187
+ permissions:
188
+ id-token: write
189
+ steps:
190
+ - uses: actions/checkout@v4
191
+ - uses: actions/download-artifact@v4
192
+ with:
193
+ path: dist
194
+ merge-multiple: true
195
+ # A tag that disagrees with Cargo.toml would upload the wrong version.
196
+ - name: Check the tag matches the package version
197
+ shell: bash
198
+ run: |
199
+ expected="${GITHUB_REF_NAME#v}"
200
+ actual="$(grep -m1 '^version = ' Cargo.toml | cut -d'"' -f2)"
201
+ if [ "$expected" != "$actual" ]; then
202
+ echo "::error::tag $GITHUB_REF_NAME does not match Cargo.toml version $actual"
203
+ exit 1
204
+ fi
205
+ ls -l dist
206
+ if ls dist | grep -v -E "^lapsed-$expected[-.]" ; then
207
+ echo "::error::dist holds files that are not version $expected"
208
+ exit 1
209
+ fi
210
+ - uses: pypa/gh-action-pypi-publish@release/v1
211
+ with:
212
+ packages-dir: dist
@@ -0,0 +1,169 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # poetry
98
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102
+ #poetry.lock
103
+
104
+ # pdm
105
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106
+ #pdm.lock
107
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108
+ # in version control.
109
+ # https://pdm.fming.dev/#use-with-ide
110
+ .pdm.toml
111
+
112
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113
+ __pypackages__/
114
+
115
+ # Celery stuff
116
+ celerybeat-schedule
117
+ celerybeat.pid
118
+
119
+ # SageMath parsed files
120
+ *.sage.py
121
+
122
+ # Environments
123
+ .env
124
+ .venv
125
+ env/
126
+ venv/
127
+ ENV/
128
+ env.bak/
129
+ venv.bak/
130
+
131
+ # Spyder project settings
132
+ .spyderproject
133
+ .spyproject
134
+
135
+ # Rope project settings
136
+ .ropeproject
137
+
138
+ # mkdocs documentation
139
+ /site
140
+
141
+ # mypy
142
+ .mypy_cache/
143
+ .dmypy.json
144
+ dmypy.json
145
+
146
+ # ruff
147
+ .ruff_cache/
148
+
149
+ # Pyre type checker
150
+ .pyre/
151
+
152
+ # pytype static type analyzer
153
+ .pytype/
154
+
155
+ # Cython debug symbols
156
+ cython_debug/
157
+
158
+ # PyCharm
159
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
160
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
161
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
162
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
163
+ #.idea/
164
+
165
+ notes
166
+
167
+ # uv lockfile for the archived Python package; generated on demand by the
168
+ # check runner, not a source of truth for anything shipped.
169
+ legacy-python/uv.lock
@@ -10,7 +10,8 @@ As of the `refactor_to_rust` branch, the implementation is **Rust**, not Python
10
10
 
11
11
  - **Language:** Rust (edition 2021), packaged for PyPI via `maturin` with `bindings = "bin"` — the wheel ships a compiled native binary + console-script shim, no PyO3/Python bindings.
12
12
  - **Entry point:** `src/main.rs` → `deadcode::cli::print_main()`
13
- - **AST parsing:** `rustpython-parser`/`rustpython-ast`
13
+ - **AST parsing:** `ruff_python_parser`/`ruff_python_ast` (Astral's parser, published on crates.io). This replaced `rustpython-parser`, whose newest release (0.4.0) tops out around Python 3.11 and could not parse 3.12+ source — see `src/actions/parse_abstract_syntax_tree.rs` for the specifics and `RUST_PORT_PLAN.md` for why the original choice was reversed.
14
+ - **Minimum Rust:** 1.95 (required by the ruff crates).
14
15
  - **Config:** `pyproject.toml` at repo root now configures the `maturin` build, not tool behavior (there is no `[tool.deadcode]` section for the Rust CLI itself yet — config merging support could be re-added if needed, but the CLI flags are the primary interface).
15
16
 
16
17
  ## Development Setup
@@ -31,7 +32,7 @@ pip install target/wheels/deadcode-*.whl
31
32
 
32
33
  ## Architecture
33
34
 
34
- Mirrors the original Python pipeline, module-for-module, with two structural differences: AST traversal is a hand-written exhaustive `match` over `rustpython_ast`'s `Stmt`/`Expr` enums (no dynamic dispatch, no Python-style `ast.iter_fields` reflection), and `NestedScope` only tracks classes (confirmed behavior-preserving by tracing what actually reads it — see `src/utils/nested_scopes.rs`'s doc comment).
35
+ Mirrors the original Python pipeline, module-for-module, with two structural differences: AST traversal is a hand-written exhaustive `match` over `ruff_python_ast`'s `Stmt`/`Expr` enums (no dynamic dispatch, no Python-style `ast.iter_fields` reflection), and `NestedScope` only tracks classes (confirmed behavior-preserving by tracing what actually reads it — see `src/utils/nested_scopes.rs`'s doc comment).
35
36
 
36
37
  1. **`src/actions/parse_arguments.rs`** — Parses CLI args (`clap`) and merges `pyproject.toml`'s `[tool.deadcode]` (if present) — mirrors `flatten_lists_of_comma_separated_values` + `parse_pyproject_toml`.
37
38
  2. **`src/actions/find_python_filenames.rs`** — Discovers `.py` files, applying `--exclude`/`--only` filters and tach.toml source-root rules.
@@ -46,12 +47,40 @@ Mirrors the original Python pipeline, module-for-module, with two structural dif
46
47
  | `src/constants.rs` | `UnusedCodeType` enum, DC01–DC13 error codes (DC10 deliberately absent) |
47
48
  | `src/data_types.rs` | `Args` struct (doubles as the `clap` CLI definition), `Part` |
48
49
  | `src/visitor/code_item.rs` | `CodeItem` — a single unused-code finding |
49
- | `src/utils/line_index.rs` | Byte-offset → (line, column) conversion (rustpython gives byte ranges, not line/col directly) |
50
+ | `src/actions/parse_abstract_syntax_tree.rs` | The only place source is parsed; pins the parser's `target_version` to the newest Python grammar |
51
+ | `src/utils/line_index.rs` | Byte-offset → (line, column) conversion (the parser gives byte ranges, not line/col directly) |
50
52
  | `src/utils/nested_scopes.rs` | Class inherits-from chain tracking |
51
53
  | `src/utils/fnmatch.rs` | Rust port of Python's `fnmatch` glob semantics |
52
- | `src/actions/remove_file_parts_from_content.rs` | Byte-level code removal for `--fix` — preserves several documented quirks/bugs from the Python original for exact parity (see its module doc comment) |
54
+ | `src/actions/get_unused_import_parts.rs` | Statement-aware removal parts for unused imports (commas, `;` separators, emptied statements) — port of upstream's `get_unused_import_parts.py` |
55
+ | `src/actions/remove_file_parts_from_content.rs` | Byte-level code removal for `--fix` — preserves the Python original's quirks except where they produce invalid Python (see its module doc comment) |
53
56
  | `src/actions/parse_tach_config.rs` | tach.toml support (source_roots, interfaces/expose, unchecked modules, tach.domain.toml merging) |
54
57
 
58
+ ### Where ruff's AST differs from CPython's `ast`
59
+
60
+ The visitor is a port of Python code and is written to match CPython's `ast`
61
+ semantics exactly. `ruff_python_ast` is not a 1:1 mirror of `ast`, so a few
62
+ places translate deliberately. Each is commented at its site; the ones worth
63
+ knowing before editing the visitor:
64
+
65
+ - **A decorated `def`/`class` node's range starts at its first decorator**, where
66
+ CPython points at the `def`/`class` keyword. `push_definition` corrects for this
67
+ via `definition_keyword_start`. Getting this wrong reports decorated definitions
68
+ on the decorator's line and silently breaks `# noqa` lookup (the comment sits on
69
+ the `def` line).
70
+ - **Merged node kinds:** `async def`/`def`, `async for`/`for`, `async with`/`with`
71
+ are one node with an `is_async` flag; `try`/`except*` is one node with `is_star`.
72
+ - **Split literals:** CPython's single `ast.Constant` is one variant per literal
73
+ kind (`StringLiteral`, `NumberLiteral`, …).
74
+ - **Restructured nodes:** `if`/`elif`/`else` is flattened into `elif_else_clauses`
75
+ rather than nested in `orelse`; `Dict` pairs keys and values in one `items` list;
76
+ `MatchClass` merges `kwd_attrs`/`kwd_patterns` into one `keywords` list.
77
+ - **f-strings/t-strings are not plain expression trees.** They are lists of parts
78
+ (to support PEP 701 and implicit concatenation), so interpolations must be walked
79
+ explicitly via `walk_interpolated_element` — this is what makes a name used only
80
+ inside `f"{x}"` count as a usage.
81
+ - **`ExprContext` has a fourth `Invalid` variant** with no CPython equivalent, used
82
+ for error-recovery nodes. Ignored.
83
+
55
84
  ### Deliberately NOT ported (confirmed dead/inert in the Python original)
56
85
 
57
86
  - `unreachable_code`/DC09 detection: computed in the Python code but explicitly excluded from `get_unused_code_items()`'s output and untested — zero observable effect, so it isn't implemented here at all.
@@ -65,6 +94,8 @@ DC01 unused-variable, DC02 unused-function, DC03 unused-class, DC04 unused-metho
65
94
 
66
95
  Unit tests live inline in `src/**` (`#[cfg(test)] mod tests`); integration tests live in `tests/*.rs`, using real temp directories (no filesystem mocking — this port always does real I/O) via the shared harness in `tests/common/mod.rs`. `tests/files/*.py` are real fixture files (not copies) whose exact line numbers are asserted against — do not reformat them without checking `tests/deadcode_integration.rs`.
67
96
 
97
+ **Parity with upstream:** `python scripts/check.py parity` runs the Rust CLI and `legacy-python/` side by side on `tests/parity/cases/*` and every legacy fixture, comparing findings, exit codes and `--dry` diffs, and checks that Rust `--fix` never leaves an unparseable file. Known differences are listed with reasons in `tests/parity/known_differences.txt`; the check fails on a new difference *and* on a listed one that disappeared, so delete the line when you fix one. `python scripts/parity.py --show <case>` prints a case's differences.
98
+
68
99
  **Run a single test:**
69
100
  ```bash
70
101
  cargo test --test fix_cli_option
lapsed-3.2.2/CLAUDE.md ADDED
@@ -0,0 +1 @@
1
+ @AGENTS.md