thailint 0.15.0__tar.gz → 0.16.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.
Files changed (233) hide show
  1. {thailint-0.15.0 → thailint-0.16.0}/CHANGELOG.md +26 -0
  2. {thailint-0.15.0 → thailint-0.16.0}/PKG-INFO +12 -7
  3. {thailint-0.15.0 → thailint-0.16.0}/README.md +8 -5
  4. {thailint-0.15.0 → thailint-0.16.0}/pyproject.toml +4 -2
  5. thailint-0.16.0/src/analyzers/rust_base.py +155 -0
  6. thailint-0.16.0/src/analyzers/rust_context.py +141 -0
  7. {thailint-0.15.0 → thailint-0.16.0}/src/cli/config.py +10 -16
  8. {thailint-0.15.0 → thailint-0.16.0}/src/cli/linters/__init__.py +5 -2
  9. {thailint-0.15.0 → thailint-0.16.0}/src/cli/linters/code_patterns.py +98 -46
  10. {thailint-0.15.0 → thailint-0.16.0}/src/cli/linters/code_smells.py +29 -29
  11. {thailint-0.15.0 → thailint-0.16.0}/src/cli/linters/documentation.py +8 -9
  12. {thailint-0.15.0 → thailint-0.16.0}/src/cli/linters/performance.py +27 -20
  13. {thailint-0.15.0 → thailint-0.16.0}/src/cli/linters/shared.py +25 -14
  14. {thailint-0.15.0 → thailint-0.16.0}/src/cli/linters/structure.py +17 -15
  15. {thailint-0.15.0 → thailint-0.16.0}/src/cli/linters/structure_quality.py +13 -15
  16. {thailint-0.15.0 → thailint-0.16.0}/src/cli/main.py +9 -12
  17. {thailint-0.15.0 → thailint-0.16.0}/src/cli/utils.py +11 -20
  18. {thailint-0.15.0 → thailint-0.16.0}/src/config.py +34 -21
  19. {thailint-0.15.0 → thailint-0.16.0}/src/core/__init__.py +14 -0
  20. {thailint-0.15.0 → thailint-0.16.0}/src/core/cli_utils.py +24 -4
  21. thailint-0.16.0/src/core/python_lint_rule.py +101 -0
  22. thailint-0.16.0/src/core/rule_aliases.py +84 -0
  23. {thailint-0.15.0 → thailint-0.16.0}/src/linter_config/ignore.py +2 -1
  24. {thailint-0.15.0 → thailint-0.16.0}/src/linter_config/rule_matcher.py +53 -8
  25. thailint-0.16.0/src/linters/cqs/__init__.py +54 -0
  26. thailint-0.16.0/src/linters/cqs/config.py +55 -0
  27. thailint-0.16.0/src/linters/cqs/function_analyzer.py +201 -0
  28. thailint-0.16.0/src/linters/cqs/input_detector.py +139 -0
  29. thailint-0.16.0/src/linters/cqs/linter.py +159 -0
  30. thailint-0.16.0/src/linters/cqs/output_detector.py +84 -0
  31. thailint-0.16.0/src/linters/cqs/python_analyzer.py +54 -0
  32. thailint-0.16.0/src/linters/cqs/types.py +82 -0
  33. thailint-0.16.0/src/linters/cqs/typescript_cqs_analyzer.py +61 -0
  34. thailint-0.16.0/src/linters/cqs/typescript_function_analyzer.py +192 -0
  35. thailint-0.16.0/src/linters/cqs/typescript_input_detector.py +203 -0
  36. thailint-0.16.0/src/linters/cqs/typescript_output_detector.py +117 -0
  37. thailint-0.16.0/src/linters/cqs/violation_builder.py +94 -0
  38. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/linter.py +79 -8
  39. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/typescript_value_extractor.py +2 -1
  40. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/violation_generator.py +70 -10
  41. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_header/linter.py +2 -1
  42. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_placement/linter.py +6 -6
  43. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_placement/pattern_validator.py +6 -5
  44. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_placement/rule_checker.py +10 -5
  45. {thailint-0.15.0 → thailint-0.16.0}/src/linters/lazy_ignores/config.py +11 -3
  46. {thailint-0.15.0 → thailint-0.16.0}/src/linters/lazy_ignores/directive_utils.py +47 -4
  47. {thailint-0.15.0 → thailint-0.16.0}/src/linters/lazy_ignores/matcher.py +42 -9
  48. {thailint-0.15.0 → thailint-0.16.0}/src/linters/lazy_ignores/python_analyzer.py +6 -2
  49. {thailint-0.15.0 → thailint-0.16.0}/src/linters/lazy_ignores/types.py +3 -1
  50. {thailint-0.15.0 → thailint-0.16.0}/src/linters/lazy_ignores/violation_builder.py +5 -1
  51. {thailint-0.15.0 → thailint-0.16.0}/src/linters/lbyl/__init__.py +3 -1
  52. thailint-0.16.0/src/linters/lbyl/linter.py +67 -0
  53. thailint-0.16.0/src/linters/lbyl/pattern_detectors/__init__.py +53 -0
  54. {thailint-0.15.0 → thailint-0.16.0}/src/linters/lbyl/pattern_detectors/base.py +24 -7
  55. thailint-0.16.0/src/linters/lbyl/pattern_detectors/dict_key_detector.py +107 -0
  56. thailint-0.16.0/src/linters/lbyl/pattern_detectors/division_check_detector.py +232 -0
  57. thailint-0.16.0/src/linters/lbyl/pattern_detectors/file_exists_detector.py +220 -0
  58. thailint-0.16.0/src/linters/lbyl/pattern_detectors/hasattr_detector.py +119 -0
  59. thailint-0.16.0/src/linters/lbyl/pattern_detectors/isinstance_detector.py +119 -0
  60. thailint-0.16.0/src/linters/lbyl/pattern_detectors/len_check_detector.py +173 -0
  61. thailint-0.16.0/src/linters/lbyl/pattern_detectors/none_check_detector.py +146 -0
  62. thailint-0.16.0/src/linters/lbyl/pattern_detectors/string_validator_detector.py +145 -0
  63. thailint-0.16.0/src/linters/lbyl/python_analyzer.py +215 -0
  64. thailint-0.16.0/src/linters/lbyl/violation_builder.py +354 -0
  65. {thailint-0.15.0 → thailint-0.16.0}/src/linters/magic_numbers/config.py +38 -7
  66. thailint-0.16.0/src/linters/magic_numbers/definition_detector.py +226 -0
  67. {thailint-0.15.0 → thailint-0.16.0}/src/linters/magic_numbers/linter.py +7 -0
  68. thailint-0.16.0/src/linters/nesting/python_analyzer.py +156 -0
  69. thailint-0.16.0/src/linters/print_statements/__init__.py +65 -0
  70. thailint-0.16.0/src/linters/print_statements/conditional_verbose_analyzer.py +200 -0
  71. thailint-0.16.0/src/linters/print_statements/conditional_verbose_rule.py +254 -0
  72. {thailint-0.15.0 → thailint-0.16.0}/src/linters/print_statements/linter.py +2 -2
  73. {thailint-0.15.0 → thailint-0.16.0}/src/linters/srp/heuristics.py +47 -14
  74. {thailint-0.15.0 → thailint-0.16.0}/src/linters/srp/typescript_metrics_calculator.py +34 -10
  75. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stateless_class/config.py +4 -0
  76. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stateless_class/linter.py +116 -4
  77. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stateless_class/python_analyzer.py +86 -4
  78. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/ignore_checker.py +4 -6
  79. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/storage.py +4 -14
  80. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/violation_generator.py +27 -13
  81. {thailint-0.15.0 → thailint-0.16.0}/src/orchestrator/language_detector.py +5 -3
  82. thailint-0.15.0/src/linters/lbyl/pattern_detectors/__init__.py +0 -25
  83. thailint-0.15.0/src/linters/nesting/python_analyzer.py +0 -93
  84. thailint-0.15.0/src/linters/print_statements/__init__.py +0 -53
  85. {thailint-0.15.0 → thailint-0.16.0}/LICENSE +0 -0
  86. {thailint-0.15.0 → thailint-0.16.0}/src/__init__.py +0 -0
  87. {thailint-0.15.0 → thailint-0.16.0}/src/analyzers/__init__.py +0 -0
  88. {thailint-0.15.0 → thailint-0.16.0}/src/analyzers/ast_utils.py +0 -0
  89. {thailint-0.15.0 → thailint-0.16.0}/src/analyzers/typescript_base.py +0 -0
  90. {thailint-0.15.0 → thailint-0.16.0}/src/api.py +0 -0
  91. {thailint-0.15.0 → thailint-0.16.0}/src/cli/__init__.py +0 -0
  92. {thailint-0.15.0 → thailint-0.16.0}/src/cli/__main__.py +0 -0
  93. {thailint-0.15.0 → thailint-0.16.0}/src/cli/config_merge.py +0 -0
  94. {thailint-0.15.0 → thailint-0.16.0}/src/cli_main.py +0 -0
  95. {thailint-0.15.0 → thailint-0.16.0}/src/core/base.py +0 -0
  96. {thailint-0.15.0 → thailint-0.16.0}/src/core/config_parser.py +0 -0
  97. {thailint-0.15.0 → thailint-0.16.0}/src/core/constants.py +0 -0
  98. {thailint-0.15.0 → thailint-0.16.0}/src/core/linter_utils.py +0 -0
  99. {thailint-0.15.0 → thailint-0.16.0}/src/core/registry.py +0 -0
  100. {thailint-0.15.0 → thailint-0.16.0}/src/core/rule_discovery.py +0 -0
  101. {thailint-0.15.0 → thailint-0.16.0}/src/core/types.py +0 -0
  102. {thailint-0.15.0 → thailint-0.16.0}/src/core/violation_builder.py +0 -0
  103. {thailint-0.15.0 → thailint-0.16.0}/src/core/violation_utils.py +0 -0
  104. {thailint-0.15.0 → thailint-0.16.0}/src/formatters/__init__.py +0 -0
  105. {thailint-0.15.0 → thailint-0.16.0}/src/formatters/sarif.py +0 -0
  106. {thailint-0.15.0 → thailint-0.16.0}/src/linter_config/__init__.py +0 -0
  107. {thailint-0.15.0 → thailint-0.16.0}/src/linter_config/directive_markers.py +0 -0
  108. {thailint-0.15.0 → thailint-0.16.0}/src/linter_config/loader.py +0 -0
  109. {thailint-0.15.0 → thailint-0.16.0}/src/linter_config/pattern_utils.py +0 -0
  110. {thailint-0.15.0 → thailint-0.16.0}/src/linters/__init__.py +0 -0
  111. {thailint-0.15.0 → thailint-0.16.0}/src/linters/collection_pipeline/__init__.py +0 -0
  112. {thailint-0.15.0 → thailint-0.16.0}/src/linters/collection_pipeline/any_all_analyzer.py +0 -0
  113. {thailint-0.15.0 → thailint-0.16.0}/src/linters/collection_pipeline/ast_utils.py +0 -0
  114. {thailint-0.15.0 → thailint-0.16.0}/src/linters/collection_pipeline/config.py +0 -0
  115. {thailint-0.15.0 → thailint-0.16.0}/src/linters/collection_pipeline/continue_analyzer.py +0 -0
  116. {thailint-0.15.0 → thailint-0.16.0}/src/linters/collection_pipeline/detector.py +0 -0
  117. {thailint-0.15.0 → thailint-0.16.0}/src/linters/collection_pipeline/filter_map_analyzer.py +0 -0
  118. {thailint-0.15.0 → thailint-0.16.0}/src/linters/collection_pipeline/linter.py +0 -0
  119. {thailint-0.15.0 → thailint-0.16.0}/src/linters/collection_pipeline/suggestion_builder.py +0 -0
  120. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/__init__.py +0 -0
  121. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/base_token_analyzer.py +0 -0
  122. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/block_filter.py +0 -0
  123. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/block_grouper.py +0 -0
  124. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/cache.py +0 -0
  125. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/cache_query.py +0 -0
  126. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/config.py +0 -0
  127. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/config_loader.py +0 -0
  128. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/constant.py +0 -0
  129. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/constant_matcher.py +0 -0
  130. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/constant_violation_builder.py +0 -0
  131. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/deduplicator.py +0 -0
  132. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/duplicate_storage.py +0 -0
  133. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/file_analyzer.py +0 -0
  134. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/inline_ignore.py +0 -0
  135. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/python_analyzer.py +0 -0
  136. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/python_constant_extractor.py +0 -0
  137. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/single_statement_detector.py +0 -0
  138. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/storage_initializer.py +0 -0
  139. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/token_hasher.py +0 -0
  140. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/typescript_analyzer.py +0 -0
  141. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/typescript_constant_extractor.py +0 -0
  142. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/typescript_statement_detector.py +0 -0
  143. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/violation_builder.py +0 -0
  144. {thailint-0.15.0 → thailint-0.16.0}/src/linters/dry/violation_filter.py +0 -0
  145. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_header/__init__.py +0 -0
  146. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_header/atemporal_detector.py +0 -0
  147. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_header/base_parser.py +0 -0
  148. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_header/bash_parser.py +0 -0
  149. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_header/config.py +0 -0
  150. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_header/css_parser.py +0 -0
  151. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_header/field_validator.py +0 -0
  152. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_header/markdown_parser.py +0 -0
  153. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_header/python_parser.py +0 -0
  154. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_header/typescript_parser.py +0 -0
  155. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_header/violation_builder.py +0 -0
  156. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_placement/__init__.py +0 -0
  157. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_placement/config_loader.py +0 -0
  158. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_placement/directory_matcher.py +0 -0
  159. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_placement/path_resolver.py +0 -0
  160. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_placement/pattern_matcher.py +0 -0
  161. {thailint-0.15.0 → thailint-0.16.0}/src/linters/file_placement/violation_factory.py +0 -0
  162. {thailint-0.15.0 → thailint-0.16.0}/src/linters/lazy_ignores/__init__.py +0 -0
  163. {thailint-0.15.0 → thailint-0.16.0}/src/linters/lazy_ignores/header_parser.py +0 -0
  164. {thailint-0.15.0 → thailint-0.16.0}/src/linters/lazy_ignores/linter.py +0 -0
  165. {thailint-0.15.0 → thailint-0.16.0}/src/linters/lazy_ignores/rule_id_utils.py +0 -0
  166. {thailint-0.15.0 → thailint-0.16.0}/src/linters/lazy_ignores/skip_detector.py +0 -0
  167. {thailint-0.15.0 → thailint-0.16.0}/src/linters/lazy_ignores/typescript_analyzer.py +0 -0
  168. {thailint-0.15.0 → thailint-0.16.0}/src/linters/lbyl/config.py +0 -0
  169. {thailint-0.15.0 → thailint-0.16.0}/src/linters/magic_numbers/__init__.py +0 -0
  170. {thailint-0.15.0 → thailint-0.16.0}/src/linters/magic_numbers/context_analyzer.py +0 -0
  171. {thailint-0.15.0 → thailint-0.16.0}/src/linters/magic_numbers/python_analyzer.py +0 -0
  172. {thailint-0.15.0 → thailint-0.16.0}/src/linters/magic_numbers/typescript_analyzer.py +0 -0
  173. {thailint-0.15.0 → thailint-0.16.0}/src/linters/magic_numbers/typescript_ignore_checker.py +0 -0
  174. {thailint-0.15.0 → thailint-0.16.0}/src/linters/magic_numbers/violation_builder.py +0 -0
  175. {thailint-0.15.0 → thailint-0.16.0}/src/linters/method_property/__init__.py +0 -0
  176. {thailint-0.15.0 → thailint-0.16.0}/src/linters/method_property/config.py +0 -0
  177. {thailint-0.15.0 → thailint-0.16.0}/src/linters/method_property/linter.py +0 -0
  178. {thailint-0.15.0 → thailint-0.16.0}/src/linters/method_property/python_analyzer.py +0 -0
  179. {thailint-0.15.0 → thailint-0.16.0}/src/linters/method_property/violation_builder.py +0 -0
  180. {thailint-0.15.0 → thailint-0.16.0}/src/linters/nesting/__init__.py +0 -0
  181. {thailint-0.15.0 → thailint-0.16.0}/src/linters/nesting/config.py +0 -0
  182. {thailint-0.15.0 → thailint-0.16.0}/src/linters/nesting/linter.py +0 -0
  183. {thailint-0.15.0 → thailint-0.16.0}/src/linters/nesting/typescript_analyzer.py +0 -0
  184. {thailint-0.15.0 → thailint-0.16.0}/src/linters/nesting/typescript_function_extractor.py +0 -0
  185. {thailint-0.15.0 → thailint-0.16.0}/src/linters/nesting/violation_builder.py +0 -0
  186. {thailint-0.15.0 → thailint-0.16.0}/src/linters/performance/__init__.py +0 -0
  187. {thailint-0.15.0 → thailint-0.16.0}/src/linters/performance/config.py +0 -0
  188. {thailint-0.15.0 → thailint-0.16.0}/src/linters/performance/constants.py +0 -0
  189. {thailint-0.15.0 → thailint-0.16.0}/src/linters/performance/linter.py +0 -0
  190. {thailint-0.15.0 → thailint-0.16.0}/src/linters/performance/python_analyzer.py +0 -0
  191. {thailint-0.15.0 → thailint-0.16.0}/src/linters/performance/regex_analyzer.py +0 -0
  192. {thailint-0.15.0 → thailint-0.16.0}/src/linters/performance/regex_linter.py +0 -0
  193. {thailint-0.15.0 → thailint-0.16.0}/src/linters/performance/typescript_analyzer.py +0 -0
  194. {thailint-0.15.0 → thailint-0.16.0}/src/linters/performance/violation_builder.py +0 -0
  195. {thailint-0.15.0 → thailint-0.16.0}/src/linters/print_statements/config.py +0 -0
  196. {thailint-0.15.0 → thailint-0.16.0}/src/linters/print_statements/python_analyzer.py +0 -0
  197. {thailint-0.15.0 → thailint-0.16.0}/src/linters/print_statements/typescript_analyzer.py +0 -0
  198. {thailint-0.15.0 → thailint-0.16.0}/src/linters/print_statements/violation_builder.py +0 -0
  199. {thailint-0.15.0 → thailint-0.16.0}/src/linters/srp/__init__.py +0 -0
  200. {thailint-0.15.0 → thailint-0.16.0}/src/linters/srp/class_analyzer.py +0 -0
  201. {thailint-0.15.0 → thailint-0.16.0}/src/linters/srp/config.py +0 -0
  202. {thailint-0.15.0 → thailint-0.16.0}/src/linters/srp/linter.py +0 -0
  203. {thailint-0.15.0 → thailint-0.16.0}/src/linters/srp/metrics_evaluator.py +0 -0
  204. {thailint-0.15.0 → thailint-0.16.0}/src/linters/srp/python_analyzer.py +0 -0
  205. {thailint-0.15.0 → thailint-0.16.0}/src/linters/srp/typescript_analyzer.py +0 -0
  206. {thailint-0.15.0 → thailint-0.16.0}/src/linters/srp/violation_builder.py +0 -0
  207. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stateless_class/__init__.py +0 -0
  208. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/__init__.py +0 -0
  209. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/config.py +0 -0
  210. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/context_filter.py +0 -0
  211. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/function_call_violation_builder.py +0 -0
  212. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/ignore_utils.py +0 -0
  213. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/linter.py +0 -0
  214. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/python/__init__.py +0 -0
  215. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/python/analyzer.py +0 -0
  216. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/python/call_tracker.py +0 -0
  217. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/python/comparison_tracker.py +0 -0
  218. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/python/condition_extractor.py +0 -0
  219. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/python/conditional_detector.py +0 -0
  220. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/python/constants.py +0 -0
  221. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/python/match_analyzer.py +0 -0
  222. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/python/validation_detector.py +0 -0
  223. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/python/variable_extractor.py +0 -0
  224. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/storage_initializer.py +0 -0
  225. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/typescript/__init__.py +0 -0
  226. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/typescript/analyzer.py +0 -0
  227. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/typescript/call_tracker.py +0 -0
  228. {thailint-0.15.0 → thailint-0.16.0}/src/linters/stringly_typed/typescript/comparison_tracker.py +0 -0
  229. {thailint-0.15.0 → thailint-0.16.0}/src/orchestrator/__init__.py +0 -0
  230. {thailint-0.15.0 → thailint-0.16.0}/src/orchestrator/core.py +0 -0
  231. {thailint-0.15.0 → thailint-0.16.0}/src/templates/thailint_config_template.yaml +0 -0
  232. {thailint-0.15.0 → thailint-0.16.0}/src/utils/__init__.py +0 -0
  233. {thailint-0.15.0 → thailint-0.16.0}/src/utils/project_root.py +0 -0
@@ -27,6 +27,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
27
27
  ### Added
28
28
 
29
29
  - **Stateless Class Linter** - Detect Python classes without state that should be module-level functions
30
+
31
+ ### Documentation
32
+
33
+ - **Parallel Processing** - Added `--parallel` flag documentation to CLI reference and README
34
+ - Documents multi-core processing with ProcessPoolExecutor (up to 8 workers)
35
+ - Explains automatic fallback to sequential for small file counts
36
+ - Provides usage guidance and performance expectations
37
+
38
+ ## [0.15.4] - 2026-01-26
39
+
40
+ ### Added
41
+
42
+ - **Inline Justifications for Lazy-Ignores** (#147) - Allow inline justifications directly next to ignore statements
43
+ - Syntax: `# noqa: PLR0912 - state machine inherently complex`
44
+ - Delimiter: ` - ` (space-dash-space) followed by justification text
45
+ - Inline justifications take precedence over header-based Suppressions
46
+ - Minimum justification length: 10 characters (configurable)
47
+ - New config options: `allow_inline_justifications`, `min_justification_length`
48
+ - Supports all ignore types: noqa, type:ignore, pylint:disable, nosec, pyright:ignore
49
+ - 27 new tests for inline justification functionality
50
+
51
+ ## [0.15.3] - 2026-01-26
52
+
53
+ ### Fixed
54
+
55
+ - **DRY Linter**: Ignore directives (`# thailint: ignore-start dry` / `ignore-end`) now work correctly for both duplicate code and duplicate constant detection (#144)
30
56
  - AST-based detection of classes without `__init__`/`__new__` constructors
31
57
  - Detects classes without instance state (`self.attr` assignments)
32
58
  - Excludes ABC, Protocol, and decorated classes (legitimate patterns)
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: thailint
3
- Version: 0.15.0
3
+ Version: 0.16.0
4
4
  Summary: The AI Linter - Enterprise-grade linting and governance for AI-generated code across multiple languages
5
5
  License: MIT
6
6
  License-File: LICENSE
7
- Keywords: linter,ai,code-quality,static-analysis,file-placement,governance,multi-language,cli,docker,python,performance,typescript
7
+ Keywords: linter,ai,code-quality,static-analysis,file-placement,governance,multi-language,cli,docker,python,performance,typescript,rust
8
8
  Author: Steve Jackson
9
9
  Requires-Python: >=3.11,<4.0
10
10
  Classifier: Development Status :: 4 - Beta
@@ -24,9 +24,11 @@ Classifier: Topic :: Software Development :: Testing
24
24
  Classifier: Topic :: Utilities
25
25
  Classifier: Typing :: Typed
26
26
  Requires-Dist: click (>=8.1.0,<9.0.0)
27
+ Requires-Dist: loguru (>=0.7.3,<0.8.0)
27
28
  Requires-Dist: pyprojroot (>=0.3.0,<0.4.0)
28
29
  Requires-Dist: pyyaml (>=6.0,<7.0)
29
30
  Requires-Dist: tree-sitter (>=0.25.2,<0.26.0)
31
+ Requires-Dist: tree-sitter-rust (>=0.23.2,<0.24.0)
30
32
  Requires-Dist: tree-sitter-typescript (>=0.23.2,<0.24.0)
31
33
  Project-URL: Documentation, https://thai-lint.readthedocs.io/
32
34
  Project-URL: Homepage, https://github.com/be-wise-be-kind/thai-lint
@@ -37,7 +39,7 @@ Description-Content-Type: text/markdown
37
39
 
38
40
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
39
41
  [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
40
- [![PyPI](https://img.shields.io/pypi/v/thai-lint)](https://pypi.org/project/thai-lint/)
42
+ [![PyPI](https://img.shields.io/pypi/v/thailint)](https://pypi.org/project/thailint/)
41
43
  [![Documentation](https://readthedocs.org/projects/thai-lint/badge/?version=latest)](https://thai-lint.readthedocs.io/)
42
44
 
43
45
  **The AI Linter** - Catch the mistakes AI coding assistants keep making.
@@ -47,7 +49,7 @@ thailint detects anti-patterns that AI tools frequently introduce: duplicate cod
47
49
  ## Installation
48
50
 
49
51
  ```bash
50
- pip install thai-lint
52
+ pip install thailint
51
53
  ```
52
54
 
53
55
  Or with Docker:
@@ -82,8 +84,9 @@ That's it. See violations, fix them, ship better code.
82
84
  | **Method Property** | Methods that should be @property | `thailint method-property src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/method-property-linter/) |
83
85
  | **File Placement** | Files in wrong directories | `thailint file-placement src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/file-placement-linter/) |
84
86
  | **Lazy Ignores** | Unjustified linting suppressions | `thailint lazy-ignores src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/lazy-ignores-linter/) |
85
- | **Print Statements** | Debug prints left in code | `thailint print-statements src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/print-statements-linter/) |
87
+ | **Improper Logging** | Print statements and conditional verbose patterns | `thailint improper-logging src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/improper-logging-linter/) |
86
88
  | **Stringly Typed** | Strings that should be enums | `thailint stringly-typed src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/stringly-typed-linter/) |
89
+ | **LBYL** | Look Before You Leap anti-patterns | `thailint lbyl src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/lbyl-linter/) |
87
90
 
88
91
  ## Configuration
89
92
 
@@ -150,10 +153,12 @@ See [How to Ignore Violations](https://thai-lint.readthedocs.io/en/latest/how-to
150
153
  - name: Run thailint
151
154
  run: |
152
155
  pip install thai-lint
153
- thailint dry src/
154
- thailint nesting src/
156
+ thailint --parallel dry src/
157
+ thailint --parallel nesting src/
155
158
  ```
156
159
 
160
+ Use `--parallel` for faster linting on large codebases (2-4x speedup on multi-core systems).
161
+
157
162
  Exit codes: `0` = success, `1` = violations found, `2` = error.
158
163
 
159
164
  ## Documentation
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
4
  [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
5
- [![PyPI](https://img.shields.io/pypi/v/thai-lint)](https://pypi.org/project/thai-lint/)
5
+ [![PyPI](https://img.shields.io/pypi/v/thailint)](https://pypi.org/project/thailint/)
6
6
  [![Documentation](https://readthedocs.org/projects/thai-lint/badge/?version=latest)](https://thai-lint.readthedocs.io/)
7
7
 
8
8
  **The AI Linter** - Catch the mistakes AI coding assistants keep making.
@@ -12,7 +12,7 @@ thailint detects anti-patterns that AI tools frequently introduce: duplicate cod
12
12
  ## Installation
13
13
 
14
14
  ```bash
15
- pip install thai-lint
15
+ pip install thailint
16
16
  ```
17
17
 
18
18
  Or with Docker:
@@ -47,8 +47,9 @@ That's it. See violations, fix them, ship better code.
47
47
  | **Method Property** | Methods that should be @property | `thailint method-property src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/method-property-linter/) |
48
48
  | **File Placement** | Files in wrong directories | `thailint file-placement src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/file-placement-linter/) |
49
49
  | **Lazy Ignores** | Unjustified linting suppressions | `thailint lazy-ignores src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/lazy-ignores-linter/) |
50
- | **Print Statements** | Debug prints left in code | `thailint print-statements src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/print-statements-linter/) |
50
+ | **Improper Logging** | Print statements and conditional verbose patterns | `thailint improper-logging src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/improper-logging-linter/) |
51
51
  | **Stringly Typed** | Strings that should be enums | `thailint stringly-typed src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/stringly-typed-linter/) |
52
+ | **LBYL** | Look Before You Leap anti-patterns | `thailint lbyl src/` | [Guide](https://thai-lint.readthedocs.io/en/latest/lbyl-linter/) |
52
53
 
53
54
  ## Configuration
54
55
 
@@ -115,10 +116,12 @@ See [How to Ignore Violations](https://thai-lint.readthedocs.io/en/latest/how-to
115
116
  - name: Run thailint
116
117
  run: |
117
118
  pip install thai-lint
118
- thailint dry src/
119
- thailint nesting src/
119
+ thailint --parallel dry src/
120
+ thailint --parallel nesting src/
120
121
  ```
121
122
 
123
+ Use `--parallel` for faster linting on large codebases (2-4x speedup on multi-core systems).
124
+
122
125
  Exit codes: `0` = success, `1` = violations found, `2` = error.
123
126
 
124
127
  ## Documentation
@@ -17,7 +17,7 @@ build-backend = "poetry.core.masonry.api"
17
17
 
18
18
  [tool.poetry]
19
19
  name = "thailint"
20
- version = "0.15.0"
20
+ version = "0.16.0"
21
21
  description = "The AI Linter - Enterprise-grade linting and governance for AI-generated code across multiple languages"
22
22
  authors = ["Steve Jackson"]
23
23
  license = "MIT"
@@ -38,6 +38,7 @@ keywords = [
38
38
  "python",
39
39
  "performance",
40
40
  "typescript",
41
+ "rust",
41
42
  ]
42
43
  classifiers = [
43
44
  "Development Status :: 4 - Beta",
@@ -75,7 +76,9 @@ click = "^8.1.0"
75
76
  pyyaml = "^6.0"
76
77
  tree-sitter = "^0.25.2"
77
78
  tree-sitter-typescript = "^0.23.2"
79
+ tree-sitter-rust = "^0.23.2"
78
80
  pyprojroot = "^0.3.0"
81
+ loguru = "^0.7.3"
79
82
 
80
83
  [tool.poetry.group.dev.dependencies]
81
84
  # Core testing and linting
@@ -102,7 +105,6 @@ xenon = "^0.9.3"
102
105
  # Comprehensive security
103
106
  safety = "^3.2.11"
104
107
  pip-audit = "^2.8.0"
105
- loguru = "^0.7.3"
106
108
  pytest-xdist = "^3.8.0"
107
109
 
108
110
  [tool.poetry.scripts]
@@ -0,0 +1,155 @@
1
+ """
2
+ Purpose: Base class for Rust AST analysis with tree-sitter parsing
3
+
4
+ Scope: Common tree-sitter initialization, parsing, and traversal utilities for Rust
5
+
6
+ Overview: Provides shared infrastructure for Rust code analysis using tree-sitter parser.
7
+ Implements common tree-sitter initialization with language setup and parser configuration.
8
+ Provides reusable parsing methods that convert Rust source to AST nodes. Includes
9
+ shared traversal utilities for walking AST trees recursively and finding nodes by type.
10
+ Delegates context-specific detection (test functions, async functions) to rust_context
11
+ module. Serves as foundation for specialized Rust analyzers (unwrap abuse, clone abuse).
12
+
13
+ Dependencies: tree-sitter, tree-sitter-rust (optional), src.analyzers.rust_context
14
+
15
+ Exports: RustBaseAnalyzer class with parsing and traversal utilities,
16
+ TREE_SITTER_RUST_AVAILABLE constant for runtime detection
17
+
18
+ Interfaces: parse_rust(code), walk_tree(node, node_type), extract_node_text(node),
19
+ is_inside_test(node), is_async_function(node)
20
+
21
+ Implementation: Tree-sitter parser singleton, recursive AST traversal, composition pattern
22
+ with rust_context helpers
23
+
24
+ Suppressions:
25
+ - type:ignore[assignment]: Tree-sitter RUST_PARSER fallback when import fails
26
+ - type:ignore[assignment,misc]: Tree-sitter Node type alias (optional dependency fallback)
27
+ """
28
+
29
+ from typing import Any
30
+
31
+ from src.analyzers import rust_context
32
+
33
+ try:
34
+ import tree_sitter_rust as tsrust
35
+ from tree_sitter import Language, Node, Parser
36
+
37
+ RUST_LANGUAGE = Language(tsrust.language())
38
+ RUST_PARSER = Parser(RUST_LANGUAGE)
39
+ TREE_SITTER_RUST_AVAILABLE = True
40
+ except ImportError:
41
+ TREE_SITTER_RUST_AVAILABLE = False
42
+ RUST_PARSER = None # type: ignore[assignment]
43
+ Node = Any # type: ignore[assignment,misc]
44
+
45
+
46
+ class RustBaseAnalyzer:
47
+ """Base analyzer for Rust code using tree-sitter."""
48
+
49
+ def __init__(self) -> None:
50
+ """Initialize Rust base analyzer."""
51
+ self.tree_sitter_available = TREE_SITTER_RUST_AVAILABLE
52
+
53
+ def parse_rust(self, code: str) -> Node | None:
54
+ """Parse Rust code to AST using tree-sitter.
55
+
56
+ Args:
57
+ code: Rust source code to parse
58
+
59
+ Returns:
60
+ Tree-sitter AST root node, or None if parsing fails or tree-sitter unavailable
61
+ """
62
+ if not TREE_SITTER_RUST_AVAILABLE or RUST_PARSER is None:
63
+ return None
64
+
65
+ tree = RUST_PARSER.parse(bytes(code, "utf8"))
66
+ return tree.root_node
67
+
68
+ def walk_tree(self, node: Node, node_type: str) -> list[Node]:
69
+ """Find all nodes of a specific type in the AST.
70
+
71
+ Recursively walks the tree and collects all nodes matching the given type.
72
+
73
+ Args:
74
+ node: Root tree-sitter node to search from
75
+ node_type: Tree-sitter node type to find (e.g., "function_item")
76
+
77
+ Returns:
78
+ List of all matching nodes
79
+ """
80
+ if not TREE_SITTER_RUST_AVAILABLE or node is None:
81
+ return []
82
+
83
+ nodes: list[Node] = []
84
+ self._walk_tree_recursive(node, node_type, nodes)
85
+ return nodes
86
+
87
+ def _walk_tree_recursive(self, node: Node, node_type: str, nodes: list[Node]) -> None:
88
+ """Recursively walk tree to find nodes of specific type.
89
+
90
+ Args:
91
+ node: Current tree-sitter node
92
+ node_type: Node type to find
93
+ nodes: List to accumulate matching nodes
94
+ """
95
+ if node.type == node_type:
96
+ nodes.append(node)
97
+
98
+ for child in node.children:
99
+ self._walk_tree_recursive(child, node_type, nodes)
100
+
101
+ def extract_node_text(self, node: Node) -> str:
102
+ """Extract text content from a tree-sitter node.
103
+
104
+ Args:
105
+ node: Tree-sitter node
106
+
107
+ Returns:
108
+ Decoded text content of the node
109
+ """
110
+ text = node.text
111
+ if text is None:
112
+ return ""
113
+ return text.decode()
114
+
115
+ def extract_identifier_name(self, node: Node) -> str:
116
+ """Extract identifier name from node children.
117
+
118
+ Common pattern for extracting names from function/struct declarations.
119
+
120
+ Args:
121
+ node: Node to extract identifier from
122
+
123
+ Returns:
124
+ Identifier name or "anonymous" fallback
125
+ """
126
+ for child in node.children:
127
+ if child.type == "identifier":
128
+ return self.extract_node_text(child)
129
+ return "anonymous"
130
+
131
+ def is_inside_test(self, node: Node) -> bool:
132
+ """Check if node is inside a test function or module.
133
+
134
+ Delegates to rust_context module for implementation.
135
+
136
+ Args:
137
+ node: Tree-sitter node to check
138
+
139
+ Returns:
140
+ True if the node is inside a test function or test module
141
+ """
142
+ return rust_context.is_inside_test(node)
143
+
144
+ def is_async_function(self, node: Node) -> bool:
145
+ """Check if a function_item is async.
146
+
147
+ Delegates to rust_context module for implementation.
148
+
149
+ Args:
150
+ node: Function item node to check
151
+
152
+ Returns:
153
+ True if the function is declared as async
154
+ """
155
+ return rust_context.is_async_function(node)
@@ -0,0 +1,141 @@
1
+ """
2
+ Purpose: Rust-specific AST context detection utilities
3
+
4
+ Scope: Helper functions for detecting test contexts and async functions in Rust code
5
+
6
+ Overview: Provides standalone helper functions for analyzing Rust AST context information.
7
+ Includes functions for detecting if code is inside a test function or module by checking
8
+ for #[test] or #[cfg(test)] attributes on preceding siblings, and for detecting async
9
+ functions by checking for function_modifiers. These utilities are designed to be used
10
+ in composition with RustBaseAnalyzer for Rust-specific lint rules that need to understand
11
+ code context.
12
+
13
+ Dependencies: tree-sitter (for Node type when available)
14
+
15
+ Exports: is_inside_test, is_async_function, has_test_attribute, has_cfg_test_attribute
16
+
17
+ Interfaces: All functions take tree-sitter Node objects and return bool
18
+
19
+ Implementation: Sibling-based attribute lookup for Rust AST structure, iterative parent
20
+ traversal for context detection
21
+
22
+ Suppressions:
23
+ - misc,assignment: Node type alias when tree-sitter optional dependency unavailable
24
+ """
25
+
26
+ from typing import Any
27
+
28
+ try:
29
+ from tree_sitter import Node
30
+
31
+ TREE_SITTER_AVAILABLE = True
32
+ except ImportError:
33
+ TREE_SITTER_AVAILABLE = False
34
+ Node = Any # type: ignore[misc,assignment]
35
+
36
+
37
+ def _get_node_text(node: Node) -> str:
38
+ """Get decoded text from a node.
39
+
40
+ Args:
41
+ node: Tree-sitter node
42
+
43
+ Returns:
44
+ Decoded text content
45
+ """
46
+ return node.text.decode() if node.text else ""
47
+
48
+
49
+ def has_test_attribute(function_node: Node) -> bool:
50
+ """Check if a function has #[test] attribute as preceding sibling.
51
+
52
+ Args:
53
+ function_node: Function item node
54
+
55
+ Returns:
56
+ True if function has #[test] attribute
57
+ """
58
+ prev_sibling = function_node.prev_sibling
59
+ while prev_sibling is not None and prev_sibling.type == "attribute_item":
60
+ if "test" in _get_node_text(prev_sibling):
61
+ return True
62
+ prev_sibling = prev_sibling.prev_sibling
63
+ return False
64
+
65
+
66
+ def has_cfg_test_attribute(mod_node: Node) -> bool:
67
+ """Check if a module has #[cfg(test)] attribute as preceding sibling.
68
+
69
+ Args:
70
+ mod_node: Module item node
71
+
72
+ Returns:
73
+ True if module has #[cfg(test)] attribute
74
+ """
75
+ prev_sibling = mod_node.prev_sibling
76
+ while prev_sibling is not None and prev_sibling.type == "attribute_item":
77
+ if "cfg(test)" in _get_node_text(prev_sibling):
78
+ return True
79
+ prev_sibling = prev_sibling.prev_sibling
80
+ return False
81
+
82
+
83
+ def is_inside_test(node: Node) -> bool:
84
+ """Check if node is inside a test function or module.
85
+
86
+ Walks up the tree looking for #[test] or #[cfg(test)] attributes.
87
+
88
+ Args:
89
+ node: Tree-sitter node to check
90
+
91
+ Returns:
92
+ True if the node is inside a test function or test module
93
+ """
94
+ current: Node | None = node
95
+ while current is not None:
96
+ if _is_test_context(current):
97
+ return True
98
+ current = current.parent
99
+ return False
100
+
101
+
102
+ def _is_test_context(node: Node) -> bool:
103
+ """Check if a node represents a test context.
104
+
105
+ Args:
106
+ node: Node to check
107
+
108
+ Returns:
109
+ True if node is a test function or test module
110
+ """
111
+ if node.type == "function_item":
112
+ return has_test_attribute(node)
113
+ if node.type == "mod_item":
114
+ return has_cfg_test_attribute(node)
115
+ return False
116
+
117
+
118
+ def is_async_function(node: Node) -> bool:
119
+ """Check if a function_item is async.
120
+
121
+ Args:
122
+ node: Function item node to check
123
+
124
+ Returns:
125
+ True if the function is declared as async
126
+ """
127
+ return any(
128
+ child.type == "function_modifiers" and _has_async_modifier(child) for child in node.children
129
+ )
130
+
131
+
132
+ def _has_async_modifier(modifiers_node: Node) -> bool:
133
+ """Check if function_modifiers node contains async keyword.
134
+
135
+ Args:
136
+ modifiers_node: The function_modifiers node
137
+
138
+ Returns:
139
+ True if async keyword is present
140
+ """
141
+ return any(modifier.type == "async" for modifier in modifiers_node.children)
@@ -21,22 +21,18 @@ Implementation: Uses Click decorators for command definition, supports multiple
21
21
  validates configuration changes before saving, uses template file for init-config generation
22
22
  """
23
23
 
24
- import logging
25
24
  import sys
26
25
  from pathlib import Path
27
26
 
28
27
  import click
29
28
  import yaml
29
+ from loguru import logger
30
30
 
31
31
  from src.config import ConfigError, save_config, validate_config
32
32
 
33
33
  from .config_merge import perform_merge
34
34
  from .main import cli
35
35
 
36
- # Configure module logger
37
- logger = logging.getLogger(__name__)
38
-
39
-
40
36
  # =============================================================================
41
37
  # Config Command Group
42
38
  # =============================================================================
@@ -150,12 +146,14 @@ def config_get(ctx: click.Context, key: str) -> None:
150
146
 
151
147
  def _convert_value_type(value: str) -> bool | int | float | str:
152
148
  """Convert string value to appropriate type."""
149
+ from contextlib import suppress
150
+
153
151
  if value.lower() in ["true", "false"]:
154
152
  return value.lower() == "true"
155
- if value.isdigit():
156
- return int(value)
157
- if value.replace(".", "", 1).isdigit() and value.count(".") == 1:
158
- return float(value)
153
+ # Use EAFP pattern for numeric conversion
154
+ for converter in (int, float):
155
+ with suppress(ValueError):
156
+ return converter(value)
159
157
  return value
160
158
 
161
159
 
@@ -175,8 +173,7 @@ def _save_and_report_success(
175
173
  """Save configuration and report success."""
176
174
  save_config(cfg, config_path)
177
175
  click.echo(f"Set {key} = {value}")
178
- if verbose:
179
- logger.info(f"Configuration updated: {key}={value}")
176
+ logger.debug(f"Configuration updated: {key}={value}")
180
177
 
181
178
 
182
179
  @config.command("set")
@@ -254,8 +251,7 @@ def config_reset(ctx: click.Context, yes: bool) -> None:
254
251
  save_config(DEFAULT_CONFIG.copy(), config_path)
255
252
  click.echo("Configuration reset to defaults")
256
253
 
257
- if ctx.obj.get("verbose"):
258
- logger.info("Configuration reset to defaults")
254
+ logger.debug("Configuration reset to defaults")
259
255
  except ConfigError as e:
260
256
  click.echo(f"Error resetting configuration: {e}", err=True)
261
257
  sys.exit(1)
@@ -460,7 +456,6 @@ def hello(ctx: click.Context, name: str, uppercase: bool) -> None:
460
456
  thai-lint hello --name Bob --uppercase
461
457
  """
462
458
  config = ctx.obj["config"]
463
- verbose = ctx.obj.get("verbose", False)
464
459
 
465
460
  # Get greeting from config or use default
466
461
  greeting_template = config.get("greeting", "Hello")
@@ -474,5 +469,4 @@ def hello(ctx: click.Context, name: str, uppercase: bool) -> None:
474
469
  # Output greeting
475
470
  click.echo(message)
476
471
 
477
- if verbose:
478
- logger.info(f"Greeted {name} with template '{greeting_template}'")
472
+ logger.debug(f"Greeted {name} with template '{greeting_template}'")
@@ -6,8 +6,9 @@ Scope: Export and registration of all linter CLI commands (nesting, srp, dry, ma
6
6
  Overview: Package initialization that imports all linter command modules to trigger their registration
7
7
  with the main CLI group via Click decorators. Each submodule defines commands using @cli.command()
8
8
  decorators that automatically register with the CLI when imported. Organized by logical grouping:
9
- structure_quality (nesting, srp), code_smells (dry, magic-numbers), code_patterns (print-statements,
9
+ structure_quality (nesting, srp), code_smells (dry, magic-numbers), code_patterns (improper-logging,
10
10
  method-property, stateless-class), structure (file-placement, pipeline), documentation (file-header).
11
+ Note: print-statements is a deprecated alias for improper-logging.
11
12
 
12
13
  Dependencies: Click for CLI framework, src.cli.main for CLI group, individual linter modules
13
14
 
@@ -34,6 +35,7 @@ from src.cli.linters import ( # noqa: F401
34
35
 
35
36
  # Re-export command functions for testing and reference
36
37
  from src.cli.linters.code_patterns import (
38
+ improper_logging,
37
39
  method_property,
38
40
  print_statements,
39
41
  stateless_class,
@@ -52,7 +54,8 @@ __all__ = [
52
54
  "dry",
53
55
  "magic_numbers",
54
56
  # Code pattern commands
55
- "print_statements",
57
+ "improper_logging",
58
+ "print_statements", # deprecated alias for improper_logging
56
59
  "method_property",
57
60
  "stateless_class",
58
61
  # Structure commands