lintro 0.9.0__tar.gz → 0.11.0__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.

Potentially problematic release.


This version of lintro might be problematic. Click here for more details.

Files changed (205) hide show
  1. {lintro-0.9.0/lintro.egg-info → lintro-0.11.0}/PKG-INFO +1 -1
  2. {lintro-0.9.0 → lintro-0.11.0}/docs/tool-analysis/ruff-analysis.md +2 -0
  3. {lintro-0.9.0 → lintro-0.11.0}/lintro/__init__.py +1 -1
  4. {lintro-0.9.0 → lintro-0.11.0/lintro.egg-info}/PKG-INFO +1 -1
  5. {lintro-0.9.0 → lintro-0.11.0}/lintro.egg-info/SOURCES.txt +4 -0
  6. {lintro-0.9.0 → lintro-0.11.0}/pyproject.toml +3 -3
  7. lintro-0.11.0/test_samples/ruff_annotations_violations.py +53 -0
  8. lintro-0.11.0/test_samples/ruff_naming_violations.py +26 -0
  9. {lintro-0.9.0 → lintro-0.11.0}/tests/cli/test_cli.py +8 -8
  10. {lintro-0.9.0 → lintro-0.11.0}/tests/conftest.py +1 -1
  11. {lintro-0.9.0 → lintro-0.11.0}/tests/formatters/test_formatters.py +16 -16
  12. {lintro-0.9.0 → lintro-0.11.0}/tests/integration/conftest.py +2 -2
  13. {lintro-0.9.0 → lintro-0.11.0}/tests/integration/test_actionlint_integration.py +3 -3
  14. {lintro-0.9.0 → lintro-0.11.0}/tests/integration/test_darglint_integration.py +4 -4
  15. {lintro-0.9.0 → lintro-0.11.0}/tests/integration/test_hadolint_integration.py +8 -8
  16. {lintro-0.9.0 → lintro-0.11.0}/tests/integration/test_prettier_integration.py +5 -5
  17. lintro-0.11.0/tests/integration/test_ruff_annotations.py +78 -0
  18. {lintro-0.9.0 → lintro-0.11.0}/tests/integration/test_ruff_integration.py +25 -22
  19. lintro-0.11.0/tests/integration/test_ruff_naming.py +31 -0
  20. {lintro-0.9.0 → lintro-0.11.0}/tests/integration/test_yamllint_integration.py +9 -9
  21. {lintro-0.9.0 → lintro-0.11.0}/tests/scripts/test_delete_previous_lintro_comments.py +5 -5
  22. {lintro-0.9.0 → lintro-0.11.0}/tests/scripts/test_ghcr_prune_untagged.py +7 -7
  23. {lintro-0.9.0 → lintro-0.11.0}/tests/scripts/test_script_environment.py +29 -17
  24. {lintro-0.9.0 → lintro-0.11.0}/tests/scripts/test_shell_scripts.py +24 -24
  25. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_ascii_normalize.py +2 -2
  26. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_bandit_parsing.py +7 -4
  27. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_black_formatter.py +3 -3
  28. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_black_parser.py +3 -3
  29. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_black_tool.py +8 -5
  30. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_black_tool_more.py +2 -2
  31. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_cli_commands.py +1 -1
  32. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_cli_commands_more.py +5 -5
  33. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_cli_programmatic.py +3 -3
  34. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_compatibility_ruff_black.py +9 -9
  35. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_config_loader.py +2 -2
  36. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_config_loader_more.py +1 -1
  37. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_console_logger.py +7 -4
  38. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_console_logger_more.py +2 -2
  39. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_enums_and_normalizers.py +6 -6
  40. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_exceptions.py +1 -1
  41. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_formatters_tables.py +4 -4
  42. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_output_manager_reports.py +3 -3
  43. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_parsers_actionlint.py +2 -2
  44. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_ruff_parser_additional.py +2 -2
  45. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_ruff_parser_more.py +4 -4
  46. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_subprocess_validator.py +4 -2
  47. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_tool_base_subprocess.py +5 -4
  48. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_tool_executor.py +29 -28
  49. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_tool_executor_more.py +22 -16
  50. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_tool_executor_post_checks.py +15 -11
  51. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_tool_manager.py +3 -3
  52. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_tool_utils.py +5 -5
  53. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_tool_utils_fallbacks.py +2 -2
  54. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_tool_utils_more.py +12 -4
  55. {lintro-0.9.0 → lintro-0.11.0}/tests/utils/test_formatting.py +3 -3
  56. {lintro-0.9.0 → lintro-0.11.0}/tests/utils/test_output_manager.py +7 -7
  57. {lintro-0.9.0 → lintro-0.11.0}/tests/utils/test_path_utils.py +7 -7
  58. {lintro-0.9.0 → lintro-0.11.0}/LICENSE +0 -0
  59. {lintro-0.9.0 → lintro-0.11.0}/MANIFEST.in +0 -0
  60. {lintro-0.9.0 → lintro-0.11.0}/README.md +0 -0
  61. {lintro-0.9.0 → lintro-0.11.0}/assets/images/coverage-badge.svg +0 -0
  62. {lintro-0.9.0 → lintro-0.11.0}/assets/images/lintro.png +0 -0
  63. {lintro-0.9.0 → lintro-0.11.0}/docs/README.md +0 -0
  64. {lintro-0.9.0 → lintro-0.11.0}/docs/configuration.md +0 -0
  65. {lintro-0.9.0 → lintro-0.11.0}/docs/contributing.md +0 -0
  66. {lintro-0.9.0 → lintro-0.11.0}/docs/coverage-setup.md +0 -0
  67. {lintro-0.9.0 → lintro-0.11.0}/docs/docker.md +0 -0
  68. {lintro-0.9.0 → lintro-0.11.0}/docs/getting-started.md +0 -0
  69. {lintro-0.9.0 → lintro-0.11.0}/docs/github-integration.md +0 -0
  70. {lintro-0.9.0 → lintro-0.11.0}/docs/lintro-self-use.md +0 -0
  71. {lintro-0.9.0 → lintro-0.11.0}/docs/security/assurance.md +0 -0
  72. {lintro-0.9.0 → lintro-0.11.0}/docs/security/requirements.md +0 -0
  73. {lintro-0.9.0 → lintro-0.11.0}/docs/style-guide.md +0 -0
  74. {lintro-0.9.0 → lintro-0.11.0}/docs/tool-analysis/README.md +0 -0
  75. {lintro-0.9.0 → lintro-0.11.0}/docs/tool-analysis/actionlint-analysis.md +0 -0
  76. {lintro-0.9.0 → lintro-0.11.0}/docs/tool-analysis/bandit-analysis.md +0 -0
  77. {lintro-0.9.0 → lintro-0.11.0}/docs/tool-analysis/black-analysis.md +0 -0
  78. {lintro-0.9.0 → lintro-0.11.0}/docs/tool-analysis/darglint-analysis.md +0 -0
  79. {lintro-0.9.0 → lintro-0.11.0}/docs/tool-analysis/hadolint-analysis.md +0 -0
  80. {lintro-0.9.0 → lintro-0.11.0}/docs/tool-analysis/prettier-analysis.md +0 -0
  81. {lintro-0.9.0 → lintro-0.11.0}/docs/tool-analysis/yamllint-analysis.md +0 -0
  82. {lintro-0.9.0 → lintro-0.11.0}/lintro/__main__.py +0 -0
  83. {lintro-0.9.0 → lintro-0.11.0}/lintro/ascii-art/fail.txt +0 -0
  84. {lintro-0.9.0 → lintro-0.11.0}/lintro/ascii-art/success.txt +0 -0
  85. {lintro-0.9.0 → lintro-0.11.0}/lintro/cli.py +0 -0
  86. {lintro-0.9.0 → lintro-0.11.0}/lintro/cli_utils/__init__.py +0 -0
  87. {lintro-0.9.0 → lintro-0.11.0}/lintro/cli_utils/commands/__init__.py +0 -0
  88. {lintro-0.9.0 → lintro-0.11.0}/lintro/cli_utils/commands/check.py +0 -0
  89. {lintro-0.9.0 → lintro-0.11.0}/lintro/cli_utils/commands/format.py +0 -0
  90. {lintro-0.9.0 → lintro-0.11.0}/lintro/cli_utils/commands/list_tools.py +0 -0
  91. {lintro-0.9.0 → lintro-0.11.0}/lintro/enums/__init__.py +0 -0
  92. {lintro-0.9.0 → lintro-0.11.0}/lintro/enums/action.py +0 -0
  93. {lintro-0.9.0 → lintro-0.11.0}/lintro/enums/darglint_strictness.py +0 -0
  94. {lintro-0.9.0 → lintro-0.11.0}/lintro/enums/group_by.py +0 -0
  95. {lintro-0.9.0 → lintro-0.11.0}/lintro/enums/hadolint_enums.py +0 -0
  96. {lintro-0.9.0 → lintro-0.11.0}/lintro/enums/output_format.py +0 -0
  97. {lintro-0.9.0 → lintro-0.11.0}/lintro/enums/tool_name.py +0 -0
  98. {lintro-0.9.0 → lintro-0.11.0}/lintro/enums/tool_type.py +0 -0
  99. {lintro-0.9.0 → lintro-0.11.0}/lintro/enums/yamllint_format.py +0 -0
  100. {lintro-0.9.0 → lintro-0.11.0}/lintro/exceptions/__init__.py +0 -0
  101. {lintro-0.9.0 → lintro-0.11.0}/lintro/exceptions/errors.py +0 -0
  102. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/__init__.py +0 -0
  103. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/core/__init__.py +0 -0
  104. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/core/output_style.py +0 -0
  105. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/core/table_descriptor.py +0 -0
  106. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/styles/__init__.py +0 -0
  107. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/styles/csv.py +0 -0
  108. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/styles/grid.py +0 -0
  109. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/styles/html.py +0 -0
  110. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/styles/json.py +0 -0
  111. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/styles/markdown.py +0 -0
  112. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/styles/plain.py +0 -0
  113. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/tools/__init__.py +0 -0
  114. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/tools/actionlint_formatter.py +0 -0
  115. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/tools/bandit_formatter.py +0 -0
  116. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/tools/black_formatter.py +0 -0
  117. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/tools/darglint_formatter.py +0 -0
  118. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/tools/hadolint_formatter.py +0 -0
  119. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/tools/prettier_formatter.py +0 -0
  120. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/tools/ruff_formatter.py +0 -0
  121. {lintro-0.9.0 → lintro-0.11.0}/lintro/formatters/tools/yamllint_formatter.py +0 -0
  122. {lintro-0.9.0 → lintro-0.11.0}/lintro/models/__init__.py +0 -0
  123. {lintro-0.9.0 → lintro-0.11.0}/lintro/models/core/__init__.py +0 -0
  124. {lintro-0.9.0 → lintro-0.11.0}/lintro/models/core/tool.py +0 -0
  125. {lintro-0.9.0 → lintro-0.11.0}/lintro/models/core/tool_config.py +0 -0
  126. {lintro-0.9.0 → lintro-0.11.0}/lintro/models/core/tool_result.py +0 -0
  127. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/__init__.py +0 -0
  128. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/actionlint/__init__.py +0 -0
  129. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/actionlint/actionlint_issue.py +0 -0
  130. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/actionlint/actionlint_parser.py +0 -0
  131. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/black/black_issue.py +0 -0
  132. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/black/black_parser.py +0 -0
  133. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/darglint/__init__.py +0 -0
  134. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/darglint/darglint_issue.py +0 -0
  135. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/darglint/darglint_parser.py +0 -0
  136. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/hadolint/__init__.py +0 -0
  137. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/hadolint/hadolint_issue.py +0 -0
  138. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/hadolint/hadolint_parser.py +0 -0
  139. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/prettier/__init__.py +0 -0
  140. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/prettier/prettier_issue.py +0 -0
  141. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/prettier/prettier_parser.py +0 -0
  142. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/ruff/__init__.py +0 -0
  143. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/ruff/ruff_issue.py +0 -0
  144. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/ruff/ruff_parser.py +0 -0
  145. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/yamllint/__init__.py +0 -0
  146. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/yamllint/yamllint_issue.py +0 -0
  147. {lintro-0.9.0 → lintro-0.11.0}/lintro/parsers/yamllint/yamllint_parser.py +0 -0
  148. {lintro-0.9.0 → lintro-0.11.0}/lintro/tools/__init__.py +0 -0
  149. {lintro-0.9.0 → lintro-0.11.0}/lintro/tools/core/__init__.py +0 -0
  150. {lintro-0.9.0 → lintro-0.11.0}/lintro/tools/core/tool_base.py +0 -0
  151. {lintro-0.9.0 → lintro-0.11.0}/lintro/tools/core/tool_manager.py +0 -0
  152. {lintro-0.9.0 → lintro-0.11.0}/lintro/tools/implementations/__init__.py +0 -0
  153. {lintro-0.9.0 → lintro-0.11.0}/lintro/tools/implementations/tool_actionlint.py +0 -0
  154. {lintro-0.9.0 → lintro-0.11.0}/lintro/tools/implementations/tool_bandit.py +0 -0
  155. {lintro-0.9.0 → lintro-0.11.0}/lintro/tools/implementations/tool_black.py +0 -0
  156. {lintro-0.9.0 → lintro-0.11.0}/lintro/tools/implementations/tool_darglint.py +0 -0
  157. {lintro-0.9.0 → lintro-0.11.0}/lintro/tools/implementations/tool_hadolint.py +0 -0
  158. {lintro-0.9.0 → lintro-0.11.0}/lintro/tools/implementations/tool_prettier.py +0 -0
  159. {lintro-0.9.0 → lintro-0.11.0}/lintro/tools/implementations/tool_ruff.py +0 -0
  160. {lintro-0.9.0 → lintro-0.11.0}/lintro/tools/implementations/tool_yamllint.py +0 -0
  161. {lintro-0.9.0 → lintro-0.11.0}/lintro/tools/tool_enum.py +0 -0
  162. {lintro-0.9.0 → lintro-0.11.0}/lintro/utils/__init__.py +0 -0
  163. {lintro-0.9.0 → lintro-0.11.0}/lintro/utils/ascii_normalize_cli.py +0 -0
  164. {lintro-0.9.0 → lintro-0.11.0}/lintro/utils/config.py +0 -0
  165. {lintro-0.9.0 → lintro-0.11.0}/lintro/utils/console_logger.py +0 -0
  166. {lintro-0.9.0 → lintro-0.11.0}/lintro/utils/formatting.py +0 -0
  167. {lintro-0.9.0 → lintro-0.11.0}/lintro/utils/output_manager.py +0 -0
  168. {lintro-0.9.0 → lintro-0.11.0}/lintro/utils/path_utils.py +0 -0
  169. {lintro-0.9.0 → lintro-0.11.0}/lintro/utils/tool_executor.py +0 -0
  170. {lintro-0.9.0 → lintro-0.11.0}/lintro/utils/tool_utils.py +0 -0
  171. {lintro-0.9.0 → lintro-0.11.0}/lintro.egg-info/dependency_links.txt +0 -0
  172. {lintro-0.9.0 → lintro-0.11.0}/lintro.egg-info/entry_points.txt +0 -0
  173. {lintro-0.9.0 → lintro-0.11.0}/lintro.egg-info/requires.txt +0 -0
  174. {lintro-0.9.0 → lintro-0.11.0}/lintro.egg-info/top_level.txt +0 -0
  175. {lintro-0.9.0 → lintro-0.11.0}/setup.cfg +0 -0
  176. {lintro-0.9.0 → lintro-0.11.0}/test_samples/Dockerfile.violations +0 -0
  177. {lintro-0.9.0 → lintro-0.11.0}/test_samples/actionlint_violations.yml +0 -0
  178. {lintro-0.9.0 → lintro-0.11.0}/test_samples/bandit_violations.py +0 -0
  179. {lintro-0.9.0 → lintro-0.11.0}/test_samples/darglint_violations.py +0 -0
  180. {lintro-0.9.0 → lintro-0.11.0}/test_samples/prettier_violations.js +0 -0
  181. {lintro-0.9.0 → lintro-0.11.0}/test_samples/ruff_black_e501_wrappable.py +0 -0
  182. {lintro-0.9.0 → lintro-0.11.0}/test_samples/ruff_clean.py +0 -0
  183. {lintro-0.9.0 → lintro-0.11.0}/test_samples/ruff_violations.py +0 -0
  184. {lintro-0.9.0 → lintro-0.11.0}/test_samples/yaml_violations.yml +0 -0
  185. {lintro-0.9.0 → lintro-0.11.0}/tests/__init__.py +0 -0
  186. {lintro-0.9.0 → lintro-0.11.0}/tests/cli/__init__.py +0 -0
  187. {lintro-0.9.0 → lintro-0.11.0}/tests/cli/conftest.py +0 -0
  188. {lintro-0.9.0 → lintro-0.11.0}/tests/formatters/__init__.py +0 -0
  189. {lintro-0.9.0 → lintro-0.11.0}/tests/formatters/conftest.py +0 -0
  190. {lintro-0.9.0 → lintro-0.11.0}/tests/integration/__init__.py +0 -0
  191. {lintro-0.9.0 → lintro-0.11.0}/tests/integration/test_bandit_integration.py +0 -0
  192. {lintro-0.9.0 → lintro-0.11.0}/tests/integration/test_ruff_black_policy.py +0 -0
  193. {lintro-0.9.0 → lintro-0.11.0}/tests/scripts/__init__.py +0 -0
  194. {lintro-0.9.0 → lintro-0.11.0}/tests/scripts/test_ci_post_pr_comment.py +0 -0
  195. {lintro-0.9.0 → lintro-0.11.0}/tests/scripts/test_extract_version.py +0 -0
  196. {lintro-0.9.0 → lintro-0.11.0}/tests/scripts/test_github_comment_utilities.py +0 -0
  197. {lintro-0.9.0 → lintro-0.11.0}/tests/scripts/test_semantic_release_compute_next.py +0 -0
  198. {lintro-0.9.0 → lintro-0.11.0}/tests/test_documentation.py +0 -0
  199. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/__init__.py +0 -0
  200. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_bandit_command_building.py +0 -0
  201. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_bandit_config_hydration.py +0 -0
  202. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_bandit_formatter_mapping.py +0 -0
  203. {lintro-0.9.0 → lintro-0.11.0}/tests/unit/test_tool_executor_fmt_exclusion.py +0 -0
  204. {lintro-0.9.0 → lintro-0.11.0}/tests/utils/__init__.py +0 -0
  205. {lintro-0.9.0 → lintro-0.11.0}/tests/utils/conftest.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lintro
3
- Version: 0.9.0
3
+ Version: 0.11.0
4
4
  Summary: A unified CLI tool for code formatting, linting, and quality assurance
5
5
  Author-email: TurboCoder13 <turbocoder13@gmail.com>
6
6
  License: MIT License
@@ -209,8 +209,10 @@ Lintro preserves all Ruff rule categories:
209
209
  | **Pyflakes** | F | Logical errors and undefined names |
210
210
  | **pycodestyle** | E, W | PEP 8 style violations |
211
211
  | **isort** | I | Import sorting issues |
212
+ | **pep8-naming** | N | Naming conventions (PEP 8) |
212
213
  | **pydocstyle** | D | Docstring style violations |
213
214
  | **pyupgrade** | UP | Python upgrade suggestions |
215
+ | **flake8-annotations** | ANN | Type annotation requirements |
214
216
  | **flake8-bugbear** | B | Bug detection and complexity |
215
217
  | **flake8-comprehensions** | C4 | Comprehension improvements |
216
218
  | **flake8-simplify** | SIM | Code simplification suggestions |
@@ -1,3 +1,3 @@
1
1
  """Lintro - A unified CLI core for code formatting, linting, and quality assurance."""
2
2
 
3
- __version__ = "0.9.0"
3
+ __version__ = "0.11.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lintro
3
- Version: 0.9.0
3
+ Version: 0.11.0
4
4
  Summary: A unified CLI tool for code formatting, linting, and quality assurance
5
5
  Author-email: TurboCoder13 <turbocoder13@gmail.com>
6
6
  License: MIT License
@@ -125,8 +125,10 @@ test_samples/actionlint_violations.yml
125
125
  test_samples/bandit_violations.py
126
126
  test_samples/darglint_violations.py
127
127
  test_samples/prettier_violations.js
128
+ test_samples/ruff_annotations_violations.py
128
129
  test_samples/ruff_black_e501_wrappable.py
129
130
  test_samples/ruff_clean.py
131
+ test_samples/ruff_naming_violations.py
130
132
  test_samples/ruff_violations.py
131
133
  test_samples/yaml_violations.yml
132
134
  tests/__init__.py
@@ -145,8 +147,10 @@ tests/integration/test_bandit_integration.py
145
147
  tests/integration/test_darglint_integration.py
146
148
  tests/integration/test_hadolint_integration.py
147
149
  tests/integration/test_prettier_integration.py
150
+ tests/integration/test_ruff_annotations.py
148
151
  tests/integration/test_ruff_black_policy.py
149
152
  tests/integration/test_ruff_integration.py
153
+ tests/integration/test_ruff_naming.py
150
154
  tests/integration/test_yamllint_integration.py
151
155
  tests/scripts/__init__.py
152
156
  tests/scripts/test_ci_post_pr_comment.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "lintro"
7
- version = "0.9.0"
7
+ version = "0.11.0"
8
8
  description = "A unified CLI tool for code formatting, linting, and quality assurance"
9
9
  keywords = [ "linting", "formatting", "code-quality", "cli", "python", "javascript", "yaml", "docker",]
10
10
  classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.13", "Topic :: Software Development :: Quality Assurance", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Utilities",]
@@ -65,8 +65,8 @@ indent-style = "space"
65
65
  skip-magic-trailing-comma = false
66
66
 
67
67
  [tool.ruff.lint]
68
- select = [ "E", "F", "W", "I", "COM", "D", "UP",]
69
- ignore = []
68
+ select = [ "E", "F", "W", "I", "COM", "N", "D", "UP", "ANN",]
69
+ ignore = [ "ANN",]
70
70
 
71
71
  [tool.ruff.pydocstyle]
72
72
  convention = "google"
@@ -0,0 +1,53 @@
1
+ """Sample file with flake8-annotations (ANN) violations for testing Ruff.
2
+
3
+ Intentionally violates several ANN-rules, such as:
4
+ - ANN101: missing type annotation for self
5
+ - ANN102: missing type annotation for cls
6
+ - ANN201: missing return type annotation for public function
7
+ - ANN204: missing return type annotation for special method
8
+ - ANN205: missing return type annotation for static method
9
+ - ANN003: missing type annotation for **kwargs
10
+ """
11
+
12
+ from typing import Any
13
+
14
+
15
+ class SampleClass:
16
+ """Sample class with annotation violations."""
17
+
18
+ def __init__(self, value: int): # ANN101: missing type for self
19
+ self.value = value
20
+
21
+ @classmethod
22
+ def from_string(cls, s: str): # ANN102: missing type for cls
23
+ return cls(int(s))
24
+
25
+ @staticmethod
26
+ def helper_func(x: int): # ANN205: missing return type
27
+ return x * 2
28
+
29
+ def __str__(self): # ANN204: missing return type for special method
30
+ return f"SampleClass({self.value})"
31
+
32
+ def public_method(self, data: list[str]): # ANN201: missing return type
33
+ return len(data)
34
+
35
+ def kwargs_method(self, **kwargs): # ANN003: missing type for **kwargs
36
+ return kwargs
37
+
38
+
39
+ def public_function(a: int, b: str): # ANN201: missing return type
40
+ """Public function without return type annotation."""
41
+ return f"{a}: {b}"
42
+
43
+
44
+ def kwargs_function(**kwargs): # ANN003: missing type for **kwargs
45
+ """Function with kwargs without type annotation."""
46
+ return kwargs
47
+
48
+
49
+ def nested_function():
50
+ """Function that returns a nested function."""
51
+ def inner(x: int): # ANN201: missing return type
52
+ return x + 1
53
+ return inner
@@ -0,0 +1,26 @@
1
+ """Sample file with pep8-naming (N) violations for testing Ruff.
2
+
3
+ Intentionally violates several N-rules, such as:
4
+ - N802: function name should be lowercase
5
+ - N803: argument name should be lowercase
6
+ - N806: variable in function should be lowercase
7
+ - N815: mixedCase variable in class scope
8
+ """
9
+
10
+
11
+ def BadFunctionName(BadArg: int) -> int: # N802, N803
12
+ BadLocal = BadArg + 1 # N806
13
+ return BadLocal
14
+
15
+
16
+ class SampleClass:
17
+ camelCaseAttr = 1 # N815
18
+
19
+ def GoodMethod(self, BadParam: int) -> int: # N803
20
+ BadLocalVar = BadParam * 2 # N806
21
+ return BadLocalVar
22
+
23
+
24
+ CONSTANT_ok = 1 # not enforcing caps here; focus on N8xx basics
25
+
26
+
@@ -9,7 +9,7 @@ from assertpy import assert_that
9
9
  from lintro.cli import cli
10
10
 
11
11
 
12
- def test_cli_help():
12
+ def test_cli_help() -> None:
13
13
  """Test that CLI shows help."""
14
14
  from click.testing import CliRunner
15
15
 
@@ -19,7 +19,7 @@ def test_cli_help():
19
19
  assert_that(result.output).contains("Lintro")
20
20
 
21
21
 
22
- def test_cli_version():
22
+ def test_cli_version() -> None:
23
23
  """Test that CLI shows version."""
24
24
  from click.testing import CliRunner
25
25
 
@@ -29,7 +29,7 @@ def test_cli_version():
29
29
  assert_that(result.output.lower()).contains("version")
30
30
 
31
31
 
32
- def test_cli_commands_registered():
32
+ def test_cli_commands_registered() -> None:
33
33
  """Test that all commands are registered."""
34
34
  from click.testing import CliRunner
35
35
 
@@ -42,7 +42,7 @@ def test_cli_commands_registered():
42
42
  assert_that(result.exit_code).is_equal_to(0)
43
43
 
44
44
 
45
- def test_main_function():
45
+ def test_main_function() -> None:
46
46
  """Test the main function."""
47
47
  from click.testing import CliRunner
48
48
 
@@ -52,7 +52,7 @@ def test_main_function():
52
52
  assert_that(result.output).contains("Lintro")
53
53
 
54
54
 
55
- def test_cli_command_aliases():
55
+ def test_cli_command_aliases() -> None:
56
56
  """Test that command aliases work."""
57
57
  from click.testing import CliRunner
58
58
 
@@ -65,7 +65,7 @@ def test_cli_command_aliases():
65
65
  assert_that(result.exit_code).is_equal_to(0)
66
66
 
67
67
 
68
- def test_cli_with_no_args():
68
+ def test_cli_with_no_args() -> None:
69
69
  """Test CLI with no arguments."""
70
70
  from click.testing import CliRunner
71
71
 
@@ -75,7 +75,7 @@ def test_cli_with_no_args():
75
75
  assert_that(result.output).is_equal_to("")
76
76
 
77
77
 
78
- def test_main_module_execution():
78
+ def test_main_module_execution() -> None:
79
79
  """Test that __main__.py can be executed directly."""
80
80
  with patch.object(sys, "argv", ["lintro", "--help"]):
81
81
  import lintro.__main__
@@ -83,7 +83,7 @@ def test_main_module_execution():
83
83
  assert_that(lintro.__main__).is_not_none()
84
84
 
85
85
 
86
- def test_main_module_as_script():
86
+ def test_main_module_as_script() -> None:
87
87
  """Test that __main__.py works when run as a script."""
88
88
  result = subprocess.run(
89
89
  [sys.executable, "-m", "lintro", "--help"],
@@ -32,7 +32,7 @@ def _ensure_test_docker_images_built() -> None:
32
32
  return
33
33
 
34
34
 
35
- def pytest_collection_modifyitems(config, items):
35
+ def pytest_collection_modifyitems(config, items) -> None:
36
36
  """Optionally skip docker tests locally unless explicitly enabled.
37
37
 
38
38
  If `LINTRO_RUN_DOCKER_TESTS` is not set to "1", mark tests under
@@ -13,7 +13,7 @@ from lintro.formatters.styles.markdown import MarkdownStyle
13
13
  from lintro.formatters.styles.plain import PlainStyle
14
14
 
15
15
 
16
- def test_output_style_abstract():
16
+ def test_output_style_abstract() -> None:
17
17
  """Test that OutputStyle is an abstract base class."""
18
18
  from abc import ABC
19
19
 
@@ -21,7 +21,7 @@ def test_output_style_abstract():
21
21
  assert_that(hasattr(OutputStyle, "format")).is_true()
22
22
 
23
23
 
24
- def test_table_descriptor_abstract():
24
+ def test_table_descriptor_abstract() -> None:
25
25
  """Test TableDescriptor is an abstract base class."""
26
26
  from abc import ABC
27
27
 
@@ -30,13 +30,13 @@ def test_table_descriptor_abstract():
30
30
  assert_that(hasattr(TableDescriptor, "get_rows")).is_true()
31
31
 
32
32
 
33
- def test_table_descriptor_methods():
33
+ def test_table_descriptor_methods() -> None:
34
34
  """Test TableDescriptor abstract methods exist."""
35
35
  assert_that(callable(TableDescriptor.get_columns)).is_true()
36
36
  assert_that(callable(TableDescriptor.get_rows)).is_true()
37
37
 
38
38
 
39
- def test_csv_style_format():
39
+ def test_csv_style_format() -> None:
40
40
  """Test CSV style formatting."""
41
41
  style = CsvStyle()
42
42
  result = style.format(["col1", "col2"], [["val1", "val2"], ["val3", "val4"]])
@@ -45,14 +45,14 @@ def test_csv_style_format():
45
45
  assert_that(result).contains("val3,val4")
46
46
 
47
47
 
48
- def test_csv_style_format_empty():
48
+ def test_csv_style_format_empty() -> None:
49
49
  """Test CSV style formatting with empty data."""
50
50
  style = CsvStyle()
51
51
  result = style.format([], [])
52
52
  assert_that(result).is_equal_to("")
53
53
 
54
54
 
55
- def test_grid_style_format():
55
+ def test_grid_style_format() -> None:
56
56
  """Test grid style formatting."""
57
57
  style = GridStyle()
58
58
  result = style.format(["col1", "col2"], [["val1", "val2"], ["val3", "val4"]])
@@ -62,14 +62,14 @@ def test_grid_style_format():
62
62
  assert_that(result).contains("val2")
63
63
 
64
64
 
65
- def test_grid_style_format_empty():
65
+ def test_grid_style_format_empty() -> None:
66
66
  """Test grid style formatting with empty data."""
67
67
  style = GridStyle()
68
68
  result = style.format([], [])
69
69
  assert_that(result).is_equal_to("")
70
70
 
71
71
 
72
- def test_grid_style_format_fallback():
72
+ def test_grid_style_format_fallback() -> None:
73
73
  """Test grid style formatting fallback when tabulate is not available."""
74
74
  style = GridStyle()
75
75
  with pytest.MonkeyPatch().context() as m:
@@ -83,7 +83,7 @@ def test_grid_style_format_fallback():
83
83
  assert_that(result).contains(" | ")
84
84
 
85
85
 
86
- def test_grid_style_format_fallback_empty():
86
+ def test_grid_style_format_fallback_empty() -> None:
87
87
  """Test grid style formatting fallback with empty data."""
88
88
  style = GridStyle()
89
89
  with pytest.MonkeyPatch().context() as m:
@@ -93,7 +93,7 @@ def test_grid_style_format_fallback_empty():
93
93
  assert_that(result).is_equal_to("")
94
94
 
95
95
 
96
- def test_grid_style_format_fallback_single_column():
96
+ def test_grid_style_format_fallback_single_column() -> None:
97
97
  """Test grid style formatting fallback with single column."""
98
98
  style = GridStyle()
99
99
  with pytest.MonkeyPatch().context() as m:
@@ -105,7 +105,7 @@ def test_grid_style_format_fallback_single_column():
105
105
  assert_that(result).contains("val2")
106
106
 
107
107
 
108
- def test_html_style_format():
108
+ def test_html_style_format() -> None:
109
109
  """Test HTML style formatting."""
110
110
  style = HtmlStyle()
111
111
  result = style.format(["col1", "col2"], [["val1", "val2"], ["val3", "val4"]])
@@ -116,7 +116,7 @@ def test_html_style_format():
116
116
  assert_that(result).contains("<td>val2</td>")
117
117
 
118
118
 
119
- def test_json_style_format():
119
+ def test_json_style_format() -> None:
120
120
  """Test JSON style formatting."""
121
121
  style = JsonStyle()
122
122
  result = style.format(["col1", "col2"], [["val1", "val2"], ["val3", "val4"]])
@@ -126,7 +126,7 @@ def test_json_style_format():
126
126
  assert_that(result).contains("val2")
127
127
 
128
128
 
129
- def test_markdown_style_format():
129
+ def test_markdown_style_format() -> None:
130
130
  """Test markdown style formatting."""
131
131
  style = MarkdownStyle()
132
132
  result = style.format(["col1", "col2"], [["val1", "val2"], ["val3", "val4"]])
@@ -135,7 +135,7 @@ def test_markdown_style_format():
135
135
  assert_that(result).contains("| val3 | val4 |")
136
136
 
137
137
 
138
- def test_plain_style_format():
138
+ def test_plain_style_format() -> None:
139
139
  """Test plain style formatting."""
140
140
  style = PlainStyle()
141
141
  result = style.format(["col1", "col2"], [["val1", "val2"], ["val3", "val4"]])
@@ -145,7 +145,7 @@ def test_plain_style_format():
145
145
  assert_that(result).contains("val2")
146
146
 
147
147
 
148
- def test_all_styles_produce_output():
148
+ def test_all_styles_produce_output() -> None:
149
149
  """Test that all styles produce some output."""
150
150
  styles = [
151
151
  CsvStyle(),
@@ -163,7 +163,7 @@ def test_all_styles_produce_output():
163
163
  assert_that(len(result) > 0).is_true()
164
164
 
165
165
 
166
- def test_styles_handle_empty_results():
166
+ def test_styles_handle_empty_results() -> None:
167
167
  """Test that all styles handle empty results gracefully."""
168
168
  styles = [
169
169
  CsvStyle(),
@@ -33,7 +33,7 @@ def test_files_dir():
33
33
 
34
34
 
35
35
  @pytest.fixture
36
- def sample_python_file():
36
+ def sample_python_file() -> str:
37
37
  """Provide a sample Python file with violations.
38
38
 
39
39
  Returns:
@@ -50,7 +50,7 @@ def sample_python_file():
50
50
 
51
51
 
52
52
  @pytest.fixture
53
- def sample_js_file():
53
+ def sample_js_file() -> str:
54
54
  """Provide a sample JavaScript file with formatting issues.
55
55
 
56
56
  Returns:
@@ -33,7 +33,7 @@ def actionlint_available() -> bool:
33
33
 
34
34
 
35
35
  @pytest.mark.actionlint
36
- def test_actionlint_available():
36
+ def test_actionlint_available() -> None:
37
37
  """Skip the suite if actionlint is not present locally.
38
38
 
39
39
  Ensures local runs behave like CI (which always has actionlint in Docker),
@@ -47,7 +47,7 @@ SAMPLE_BAD = Path("test_samples/actionlint_violations.yml")
47
47
 
48
48
 
49
49
  @pytest.mark.actionlint
50
- def test_actionlint_reports_violations(tmp_path):
50
+ def test_actionlint_reports_violations(tmp_path) -> None:
51
51
  """Assert that Lintro detects violations reported by actionlint.
52
52
 
53
53
  Args:
@@ -71,7 +71,7 @@ def test_actionlint_reports_violations(tmp_path):
71
71
 
72
72
 
73
73
  @pytest.mark.actionlint
74
- def test_actionlint_no_files(tmp_path):
74
+ def test_actionlint_no_files(tmp_path) -> None:
75
75
  """Assert that Lintro succeeds when no workflow files are present.
76
76
 
77
77
  Args:
@@ -65,7 +65,7 @@ def _ensure_darglint_cli_available() -> None:
65
65
  pytest.skip("darglint CLI not installed/runnable; skipping direct CLI test")
66
66
 
67
67
 
68
- def test_darglint_reports_violations_direct(tmp_path):
68
+ def test_darglint_reports_violations_direct(tmp_path) -> None:
69
69
  """Darglint CLI: Should detect and report violations in a sample file.
70
70
 
71
71
  Args:
@@ -82,7 +82,7 @@ def test_darglint_reports_violations_direct(tmp_path):
82
82
  assert "DAR" in output, "Darglint output should contain error codes."
83
83
 
84
84
 
85
- def test_darglint_reports_violations_through_lintro(tmp_path):
85
+ def test_darglint_reports_violations_through_lintro(tmp_path) -> None:
86
86
  """Lintro DarglintTool: Should detect and report violations in a sample file.
87
87
 
88
88
  Args:
@@ -111,7 +111,7 @@ def test_darglint_reports_violations_through_lintro(tmp_path):
111
111
  ), "Lintro DarglintTool output should contain error codes."
112
112
 
113
113
 
114
- def test_darglint_output_consistency_direct_vs_lintro(tmp_path):
114
+ def test_darglint_output_consistency_direct_vs_lintro(tmp_path) -> None:
115
115
  """Darglint CLI vs Lintro: Should produce consistent results for the same file.
116
116
 
117
117
  Args:
@@ -137,7 +137,7 @@ def test_darglint_output_consistency_direct_vs_lintro(tmp_path):
137
137
  # Optionally compare error codes if output format is stable
138
138
 
139
139
 
140
- def test_darglint_fix_method_not_implemented(tmp_path):
140
+ def test_darglint_fix_method_not_implemented(tmp_path) -> None:
141
141
  """Lintro DarglintTool: .fix() should raise NotImplementedError.
142
142
 
143
143
  Args:
@@ -69,7 +69,7 @@ def run_hadolint_directly(file_path: Path) -> tuple[bool, str, int]:
69
69
 
70
70
 
71
71
  @pytest.mark.hadolint
72
- def test_hadolint_available():
72
+ def test_hadolint_available() -> None:
73
73
  """Check if hadolint is available in PATH."""
74
74
  try:
75
75
  result = subprocess.run(
@@ -85,7 +85,7 @@ def test_hadolint_available():
85
85
 
86
86
 
87
87
  @pytest.mark.hadolint
88
- def test_hadolint_reports_violations_direct(tmp_path):
88
+ def test_hadolint_reports_violations_direct(tmp_path) -> None:
89
89
  """Hadolint CLI: Should detect and report violations in a sample file.
90
90
 
91
91
  Args:
@@ -115,7 +115,7 @@ def test_hadolint_reports_violations_direct(tmp_path):
115
115
 
116
116
 
117
117
  @pytest.mark.hadolint
118
- def test_hadolint_reports_violations_through_lintro(tmp_path):
118
+ def test_hadolint_reports_violations_through_lintro(tmp_path) -> None:
119
119
  """Lintro HadolintTool: Should detect and report violations in a sample file.
120
120
 
121
121
  Args:
@@ -145,7 +145,7 @@ def test_hadolint_reports_violations_through_lintro(tmp_path):
145
145
 
146
146
 
147
147
  @pytest.mark.hadolint
148
- def test_hadolint_output_consistency_direct_vs_lintro(tmp_path):
148
+ def test_hadolint_output_consistency_direct_vs_lintro(tmp_path) -> None:
149
149
  """Hadolint CLI vs Lintro: Should produce consistent results for the same file.
150
150
 
151
151
  Args:
@@ -184,7 +184,7 @@ def test_hadolint_output_consistency_direct_vs_lintro(tmp_path):
184
184
 
185
185
 
186
186
  @pytest.mark.hadolint
187
- def test_hadolint_with_ignore_rules(tmp_path):
187
+ def test_hadolint_with_ignore_rules(tmp_path) -> None:
188
188
  """Lintro HadolintTool: Should properly ignore specified rules.
189
189
 
190
190
  Args:
@@ -206,7 +206,7 @@ def test_hadolint_with_ignore_rules(tmp_path):
206
206
 
207
207
 
208
208
  @pytest.mark.hadolint
209
- def test_hadolint_fix_method_not_implemented(tmp_path):
209
+ def test_hadolint_fix_method_not_implemented(tmp_path) -> None:
210
210
  """Lintro HadolintTool: .fix() should raise NotImplementedError.
211
211
 
212
212
  Args:
@@ -225,7 +225,7 @@ def test_hadolint_fix_method_not_implemented(tmp_path):
225
225
 
226
226
 
227
227
  @pytest.mark.hadolint
228
- def test_hadolint_empty_directory(tmp_path):
228
+ def test_hadolint_empty_directory(tmp_path) -> None:
229
229
  """Lintro HadolintTool: Should handle empty directories gracefully.
230
230
 
231
231
  Args:
@@ -243,7 +243,7 @@ def test_hadolint_empty_directory(tmp_path):
243
243
 
244
244
 
245
245
  @pytest.mark.hadolint
246
- def test_hadolint_parser_validation(tmp_path):
246
+ def test_hadolint_parser_validation(tmp_path) -> None:
247
247
  """Test that hadolint parser correctly parses output.
248
248
 
249
249
  Args:
@@ -68,7 +68,7 @@ def run_prettier_directly(
68
68
  return success, full_output, issues_count
69
69
 
70
70
 
71
- def test_prettier_reports_violations_direct(temp_prettier_file):
71
+ def test_prettier_reports_violations_direct(temp_prettier_file) -> None:
72
72
  """Prettier CLI: Should detect and report violations in a sample file.
73
73
 
74
74
  Args:
@@ -84,7 +84,7 @@ def test_prettier_reports_violations_direct(temp_prettier_file):
84
84
  assert has_warnings, "Prettier output should contain warning indicators."
85
85
 
86
86
 
87
- def test_prettier_reports_violations_through_lintro(temp_prettier_file):
87
+ def test_prettier_reports_violations_through_lintro(temp_prettier_file) -> None:
88
88
  """Lintro PrettierTool: Should detect and report violations in a sample file.
89
89
 
90
90
  Args:
@@ -109,7 +109,7 @@ def test_prettier_reports_violations_through_lintro(temp_prettier_file):
109
109
  assert has_warnings, "Lintro PrettierTool output should contain warning indicators."
110
110
 
111
111
 
112
- def test_prettier_fix_method(temp_prettier_file):
112
+ def test_prettier_fix_method(temp_prettier_file) -> None:
113
113
  """Lintro PrettierTool: Should fix formatting issues.
114
114
 
115
115
  Args:
@@ -147,7 +147,7 @@ def test_prettier_fix_method(temp_prettier_file):
147
147
  assert final_result.issues_count == 0, "Should have no issues after fixing"
148
148
 
149
149
 
150
- def test_prettier_output_consistency_direct_vs_lintro(temp_prettier_file):
150
+ def test_prettier_output_consistency_direct_vs_lintro(temp_prettier_file) -> None:
151
151
  """Prettier CLI vs Lintro: Should produce consistent results for the same file.
152
152
 
153
153
  Args:
@@ -178,7 +178,7 @@ def test_prettier_output_consistency_direct_vs_lintro(temp_prettier_file):
178
178
  )
179
179
 
180
180
 
181
- def test_prettier_fix_sets_issues_for_table(temp_prettier_file):
181
+ def test_prettier_fix_sets_issues_for_table(temp_prettier_file) -> None:
182
182
  """PrettierTool.fix should populate issues for table rendering.
183
183
 
184
184
  Args:
@@ -0,0 +1,78 @@
1
+ """Integration tests for Ruff flake8-annotations (ANN) rule family."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import shutil
7
+ import tempfile
8
+
9
+ from assertpy import assert_that
10
+
11
+ from lintro.tools.implementations.tool_ruff import RuffTool
12
+
13
+
14
+ def test_annotations_rules_detected() -> None:
15
+ """Ensure Ruff reports ANN-family violations on a known sample file."""
16
+ sample = os.path.abspath("test_samples/ruff_annotations_violations.py")
17
+ with tempfile.TemporaryDirectory() as tmp:
18
+ test_file = os.path.join(tmp, "ruff_annotations_case.py")
19
+ shutil.copy(sample, test_file)
20
+
21
+ ruff = RuffTool()
22
+ ruff.set_options(select=["ANN"]) # only ANN rules
23
+ result = ruff.check([test_file])
24
+
25
+ assert_that(result.success).is_false()
26
+ codes = [getattr(i, "code", "") for i in (result.issues or [])]
27
+ # Expect several representative ANN-codes
28
+ assert_that(any(code.startswith("ANN") for code in codes)).is_true()
29
+ assert_that(
30
+ any(
31
+ code in {"ANN101", "ANN102", "ANN201", "ANN204", "ANN205", "ANN003"}
32
+ for code in codes
33
+ ),
34
+ ).is_true()
35
+
36
+
37
+ def test_annotations_rules_with_other_rules() -> None:
38
+ """Ensure ANN rules work alongside other rule families."""
39
+ sample = os.path.abspath("test_samples/ruff_annotations_violations.py")
40
+ with tempfile.TemporaryDirectory() as tmp:
41
+ test_file = os.path.join(tmp, "ruff_annotations_mixed.py")
42
+ shutil.copy(sample, test_file)
43
+
44
+ ruff = RuffTool()
45
+ ruff.set_options(select=["ANN", "F"]) # ANN + pyflakes errors
46
+ result = ruff.check([test_file])
47
+
48
+ assert_that(result.success).is_false()
49
+ codes = [getattr(i, "code", "") for i in (result.issues or [])]
50
+ # Should have ANN codes (F codes may not be present in this sample)
51
+ assert_that(any(code.startswith("ANN") for code in codes)).is_true()
52
+
53
+
54
+ def test_annotations_rules_fix_capability() -> None:
55
+ """Test that ANN rules can be fixed automatically where possible."""
56
+ sample = os.path.abspath("test_samples/ruff_annotations_violations.py")
57
+ with tempfile.TemporaryDirectory() as tmp:
58
+ test_file = os.path.join(tmp, "ruff_annotations_fix.py")
59
+ shutil.copy(sample, test_file)
60
+
61
+ ruff = RuffTool()
62
+ ruff.set_options(select=["ANN"])
63
+
64
+ # Check initial issues
65
+ initial_result = ruff.check([test_file])
66
+ initial_count = len(initial_result.issues or [])
67
+
68
+ # Apply fixes
69
+ ruff.fix([test_file])
70
+
71
+ # Check remaining issues after fix
72
+ final_result = ruff.check([test_file])
73
+ final_count = len(final_result.issues or [])
74
+
75
+ # Some issues should be fixed (though ANN rules are often not auto-fixable)
76
+ # We mainly verify the fix process doesn't crash and reduces issue count
77
+ assert_that(initial_count).is_greater_than_or_equal_to(final_count)
78
+ # Fix result may be False if issues remain, which is expected for ANN rules