sarj-python-lint 1.63.0__tar.gz → 1.63.1__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 (238) hide show
  1. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/PKG-INFO +1 -1
  2. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/pyproject.toml +1 -1
  3. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_fixed_sleep_in_loop.py +6 -1
  4. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_offset_pagination.py +32 -10
  5. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_select_star.py +2 -16
  6. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_native_string_check.py +1 -8
  7. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +9 -21
  8. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +2 -3
  9. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +2 -2
  10. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/.gitignore +0 -0
  11. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/LICENSE +0 -0
  12. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/README.md +0 -0
  13. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/__init__.py +0 -0
  14. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/__main__.py +0 -0
  15. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/_analysis_session.py +0 -0
  16. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/_file_context.py +0 -0
  17. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/_filesystem.py +0 -0
  18. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/_python_target.py +0 -0
  19. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/_ratchet_cli.py +0 -0
  20. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/_secret_names.py +0 -0
  21. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/_source.py +0 -0
  22. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/_version.py +0 -0
  23. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/benchmark.py +0 -0
  24. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/cast_access.py +0 -0
  25. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/interpreter_argv.py +0 -0
  26. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/json_boundary.py +0 -0
  27. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/py.typed +0 -0
  28. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/ratchet.py +0 -0
  29. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rule_base.py +0 -0
  30. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/__init__.py +0 -0
  31. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
  32. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_ast_index.py +0 -0
  33. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_ast_position.py +0 -0
  34. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_closed_helpers.py +0 -0
  35. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_comments.py +0 -0
  36. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
  37. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_copy_on_write.py +0 -0
  38. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_data_union_discriminator.py +0 -0
  39. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
  40. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_docstrings.py +0 -0
  41. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_exports.py +0 -0
  42. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_fastapi.py +0 -0
  43. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_first_party.py +0 -0
  44. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
  45. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_imports.py +0 -0
  46. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_inert_model_annotation.py +0 -0
  47. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_inherited_contract.py +0 -0
  48. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_local_source.py +0 -0
  49. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_logging.py +0 -0
  50. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_mapping_shape_callbacks.py +0 -0
  51. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_namespace_access.py +0 -0
  52. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_native_namespace_capability.py +0 -0
  53. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
  54. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_paths.py +0 -0
  55. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_project_index.py +0 -0
  56. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
  57. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_pydantic_field_contract.py +0 -0
  58. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_pytest.py +0 -0
  59. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_registry.py +0 -0
  60. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_resolved_operation_signature.py +0 -0
  61. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
  62. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_route_shapes.py +0 -0
  63. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_runtime_bindings.py +0 -0
  64. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_set_fields.py +0 -0
  65. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_sql.py +0 -0
  66. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_static_json_alias.py +0 -0
  67. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_store_writes.py +0 -0
  68. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
  69. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
  70. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_test_composition.py +0 -0
  71. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_test_provenance.py +0 -0
  72. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/_type_guard_symbols.py +0 -0
  73. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
  74. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
  75. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
  76. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
  77. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/delete_route_returns_no_content.py +0 -0
  78. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
  79. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
  80. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/duplicate_adjacent_exception_handler.py +0 -0
  81. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/duplicate_closed_pure_helper.py +0 -0
  82. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
  83. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
  84. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
  85. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
  86. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
  87. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
  88. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
  89. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
  90. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
  91. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
  92. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
  93. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_async_function_cache.py +0 -0
  94. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_before_validator_input_mutation.py +0 -0
  95. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_broad_keyword_capture.py +0 -0
  96. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
  97. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_conflicting_pydantic_alias_validation.py +0 -0
  98. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
  99. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_contradictory_type_guard.py +0 -0
  100. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
  101. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
  102. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_create_verb_in_post_path.py +0 -0
  103. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
  104. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_defaulted_environment_setting.py +0 -0
  105. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
  106. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_discarded_validation_result.py +0 -0
  107. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_dual_shape_model_field_reader.py +0 -0
  108. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
  109. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
  110. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_duplicate_field_validator_body.py +0 -0
  111. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_exception_text_in_500_detail.py +0 -0
  112. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
  113. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
  114. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
  115. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
  116. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
  117. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_folded_bad_request_not_found.py +0 -0
  118. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
  119. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
  120. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_hasattr.py +0 -0
  121. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
  122. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_impossible_pydantic_field_bounds.py +0 -0
  123. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
  124. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_input_model_mutation.py +0 -0
  125. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_interpreter_source_arguments.py +0 -0
  126. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
  127. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_invalid_pydantic_bypass.py +0 -0
  128. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_invalid_pydantic_validator_return.py +0 -0
  129. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_loguru_exc_info.py +0 -0
  130. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_loguru_printf_format.py +0 -0
  131. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_mocked_pydantic_value_object.py +0 -0
  132. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_mutating_container_transform.py +0 -0
  133. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
  134. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
  135. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_partial_type_is.py +0 -0
  136. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
  137. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
  138. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
  139. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
  140. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
  141. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
  142. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
  143. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
  144. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
  145. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
  146. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
  147. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
  148. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
  149. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_shallow_record_type_guard.py +0 -0
  150. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_slash_collection_root_under_prefix.py +0 -0
  151. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
  152. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
  153. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
  154. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_test_method_grafting.py +0 -0
  155. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
  156. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
  157. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_unknown_pydantic_validator_field.py +0 -0
  158. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
  159. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_unused_copy_result.py +0 -0
  160. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +0 -0
  161. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
  162. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
  163. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
  164. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/no_work_verb_get_route.py +0 -0
  165. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
  166. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
  167. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
  168. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +0 -0
  169. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_bulk_upsert.py +0 -0
  170. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
  171. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
  172. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
  173. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_declarative_batch_validation.py +0 -0
  174. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_discriminated_model_union.py +0 -0
  175. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
  176. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
  177. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
  178. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
  179. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
  180. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
  181. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
  182. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
  183. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
  184. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
  185. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
  186. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
  187. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
  188. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
  189. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
  190. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_psycopg_executemany.py +0 -0
  191. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
  192. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +0 -0
  193. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
  194. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_required_constructor_parameters.py +0 -0
  195. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
  196. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
  197. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
  198. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
  199. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
  200. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
  201. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
  202. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
  203. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
  204. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
  205. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
  206. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
  207. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/redundant_test_constructor_forwarder.py +0 -0
  208. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
  209. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
  210. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
  211. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/repeated_unimplemented_test_contract.py +0 -0
  212. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/require_exp_on_jwt_decode.py +0 -0
  213. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
  214. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
  215. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
  216. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/require_injectable_retry_sleep.py +0 -0
  217. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
  218. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
  219. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
  220. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/require_precise_factory_signature.py +0 -0
  221. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
  222. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
  223. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/require_pydantic_for_mapping_shape.py +0 -0
  224. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
  225. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
  226. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
  227. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/stepdown.py +0 -0
  228. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/store_field_update_reuses_upsert.py +0 -0
  229. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
  230. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
  231. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
  232. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/test_without_explicit_oracle.py +0 -0
  233. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
  234. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
  235. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
  236. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
  237. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
  238. {sarj_python_lint-1.63.0 → sarj_python_lint-1.63.1}/src/sarj_python_lint/rules/unused_test_factory_option.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sarj-python-lint
3
- Version: 1.63.0
3
+ Version: 1.63.1
4
4
  Summary: Custom Python lint rules — AST-based, pre-commit-friendly, hypermodern defaults
5
5
  Project-URL: Homepage, https://code-standards.sarj.ai/rules/python/
6
6
  Project-URL: Documentation, https://code-standards.sarj.ai/rules/python/
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sarj-python-lint"
3
- version = "1.63.0"
3
+ version = "1.63.1"
4
4
  description = "Custom Python lint rules — AST-based, pre-commit-friendly, hypermodern defaults"
5
5
  readme = "README.md"
6
6
  authors = [{ name = "sarj-ai" }]
@@ -235,7 +235,12 @@ def _folded_seconds(node: ast.expr | None, constants: Mapping[str, float]) -> fl
235
235
  return None if value is None else -value
236
236
  case ast.BinOp(left=left, op=op, right=right):
237
237
  lhs, rhs = _folded_seconds(left, constants), _folded_seconds(right, constants)
238
- return None if lhs is None or rhs is None else _arithmetic(op, lhs, rhs)
238
+ if lhs is None or rhs is None:
239
+ return None
240
+ try:
241
+ return _arithmetic(op, lhs, rhs)
242
+ except OverflowError:
243
+ return None
239
244
  case _:
240
245
  return None
241
246
 
@@ -60,7 +60,7 @@ class NoOffsetPagination(Rule):
60
60
  category=RuleCategory.PERFORMANCE,
61
61
  autofix=AutofixPolicy.NONE,
62
62
  limitations=(
63
- "Only SQL string literals in recognized store modules are analyzed.",
63
+ "Only SQL string literals, f-strings, and their static concatenations in recognized store modules are analyzed.",
64
64
  "Only dynamic OFFSET values in credible SELECT queries are reported; fixed ordinal offsets are excluded.",
65
65
  "Parenthesized arithmetic and common numeric wrappers such as GREATEST, LEAST, and COALESCE preserve the dynamic driver marker. Arbitrary SQL functions and procedural values remain opaque.",
66
66
  "Generated files, migrations, docstrings, comments, quoted identifiers, and BigQuery `WITH OFFSET AS` array indexing are excluded.",
@@ -95,6 +95,36 @@ class NoOffsetPagination(Rule):
95
95
  expected_count=0,
96
96
  public=True,
97
97
  ),
98
+ RuleExample(
99
+ example_id="concatenated-dynamic-offset",
100
+ title="Concatenation retains a dynamic offset",
101
+ outcome=ExampleOutcome.MATCH,
102
+ files=(
103
+ ExampleFile.python(
104
+ "app/task_store.py",
105
+ "QUERY = 'SELECT id FROM task ORDER BY id ' + f'LIMIT 10 OFFSET {offset}'\n",
106
+ ),
107
+ ),
108
+ focus_path=PurePosixPath("app/task_store.py"),
109
+ expected_count=1,
110
+ scenario="concatenated-sql",
111
+ public=True,
112
+ ),
113
+ RuleExample(
114
+ example_id="concatenated-static-offset",
115
+ title="A dynamic limit does not make the offset dynamic",
116
+ outcome=ExampleOutcome.NO_MATCH,
117
+ files=(
118
+ ExampleFile.python(
119
+ "app/task_store.py",
120
+ "QUERY = f'SELECT id FROM task LIMIT {limit} ' + 'OFFSET 2'\n",
121
+ ),
122
+ ),
123
+ focus_path=PurePosixPath("app/task_store.py"),
124
+ expected_count=0,
125
+ scenario="concatenated-sql",
126
+ public=True,
127
+ ),
98
128
  ),
99
129
  )
100
130
  description = documentation.summary
@@ -168,15 +198,7 @@ def _has_dynamic_numeric_offset(sql: str) -> bool:
168
198
 
169
199
 
170
200
  def _sql_value(node: ast.expr) -> str | None:
171
- if isinstance(node, ast.JoinedStr):
172
- pieces: list[str] = []
173
- for value in node.values:
174
- if isinstance(value, ast.Constant) and isinstance(value.value, str):
175
- pieces.append(value.value)
176
- elif isinstance(value, ast.FormattedValue):
177
- pieces.append(":__sarj_dynamic__")
178
- return "".join(pieces)
179
- return sql_string_value(node)
201
+ return sql_string_value(node, interpolation_placeholder=":__sarj_dynamic__")
180
202
 
181
203
 
182
204
  def _mask_dialect_noise(sql: str) -> str:
@@ -15,7 +15,7 @@ from sarj_python_lint.rule_base import (
15
15
  RuleDocumentation,
16
16
  RuleExample,
17
17
  )
18
- from sarj_python_lint.rules._ast_index import walk, walk as walk_ast
18
+ from sarj_python_lint.rules._ast_index import walk
19
19
  from sarj_python_lint.rules._paths import is_test_path
20
20
  from sarj_python_lint.rules._sql import sql_string_value, strip_sql_noise
21
21
 
@@ -24,7 +24,6 @@ if TYPE_CHECKING:
24
24
  from collections.abc import Mapping
25
25
 
26
26
  from sarj_python_lint._file_context import PythonFileContext
27
- from sarj_python_lint.rules._ast_index import NodeIndex
28
27
 
29
28
 
30
29
  _SQL_TOKEN = re.compile(r"[A-Za-z_][A-Za-z0-9_$]*|\d+(?:\.\d+)?|[(),.*;]")
@@ -179,7 +178,7 @@ class NoSelectStar(Rule):
179
178
 
180
179
  diags: list[Diagnostic] = []
181
180
  parents = context.parents
182
- docstrings = _docstring_value_ids(tree, node_index=context.node_index)
181
+ docstrings = context.docstring_node_ids
183
182
  consumed: set[int] = set()
184
183
  for node in context.nodes(ast.Constant, ast.BinOp, ast.JoinedStr):
185
184
  if id(node) in consumed or id(node) in docstrings or not _is_query_context(node, parents):
@@ -210,19 +209,6 @@ class NoSelectStar(Rule):
210
209
  return diags
211
210
 
212
211
 
213
- def _docstring_value_ids(tree: ast.AST, *, node_index: NodeIndex | None = None) -> set[int]:
214
- owners = (ast.Module, ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)
215
- return {
216
- id(owner.body[0].value)
217
- for owner in walk_ast(tree, index=node_index)
218
- if isinstance(owner, owners)
219
- and owner.body
220
- and isinstance(owner.body[0], ast.Expr)
221
- and isinstance(owner.body[0].value, ast.Constant)
222
- and isinstance(owner.body[0].value.value, str)
223
- }
224
-
225
-
226
212
  def _is_query_context(node: ast.expr, parents: Mapping[ast.AST, ast.AST]) -> bool:
227
213
  current: ast.AST = node
228
214
  while (parent := parents.get(current)) is not None:
@@ -241,14 +241,7 @@ def _plain_string_adapter(
241
241
  value = _single_value(node, "type")
242
242
  if value is None:
243
243
  return False
244
- return (
245
- isinstance(value, ast.Name)
246
- and value.id == "str"
247
- and context.imports.builtin_is_unshadowed("str")
248
- and _lexical_binding("str", value, provenance) is None
249
- and "builtins" not in unsafe_imports
250
- and "builtins.str" not in unsafe_imports
251
- ) or _resolves(value, context, provenance, imports, unsafe_imports, sources=_BUILTINS, symbol="str")
244
+ return _builtin_type(value, context, provenance, imports, unsafe_imports, symbol="str")
252
245
 
253
246
 
254
247
  def _single_value(call: ast.Call, keyword: str) -> ast.expr | None:
@@ -198,9 +198,15 @@ def _is_candidate_pair(assignment: ast.stmt, condition: ast.stmt) -> bool:
198
198
  def _check_body(node: ast.AST, body: list[ast.stmt], context: _AnalysisContext) -> list[Diagnostic]:
199
199
  owner = _lexical_owner(node, context.parents)
200
200
  state = _body_state(node, owner, body, context)
201
+ last_uses = {
202
+ child.id: index
203
+ for index, statement in enumerate(body)
204
+ for child in walk(statement)
205
+ if isinstance(child, ast.Name)
206
+ }
201
207
  diagnostics: list[Diagnostic] = []
202
208
  for index in range(len(body) - 1):
203
- diagnostic = _diagnostic_for_pair(body, index, state, context)
209
+ diagnostic = _diagnostic_for_pair(body, index, state, context, last_uses)
204
210
  if diagnostic is not None:
205
211
  diagnostics.append(diagnostic)
206
212
  return diagnostics
@@ -262,6 +268,7 @@ def _diagnostic_for_pair(
262
268
  index: int,
263
269
  state: _BodyState,
264
270
  context: _AnalysisContext,
271
+ last_uses: Mapping[str, int],
265
272
  ) -> Diagnostic | None:
266
273
  assignment, condition = body[index], body[index + 1]
267
274
  if not (
@@ -282,9 +289,7 @@ def _diagnostic_for_pair(
282
289
  annotated_names=state.annotated_names,
283
290
  ):
284
291
  return None
285
- if _is_name_used_after(body, index + 2, name) or is_suppressed(
286
- context.source_lines, assignment.lineno, context.code
287
- ):
292
+ if last_uses.get(name, -1) >= index + 2 or is_suppressed(context.source_lines, assignment.lineno, context.code):
288
293
  return None
289
294
  return Diagnostic(
290
295
  path=context.path,
@@ -316,23 +321,6 @@ def _is_regex_call(
316
321
  )
317
322
 
318
323
 
319
- def _is_name_used_after(stmts: list[ast.stmt], start_idx: int, name: str) -> bool:
320
- class UsageVisitor(ast.NodeVisitor):
321
- used: bool = False
322
-
323
- def visit_Name(self, node: ast.Name) -> None:
324
- if node.id == name:
325
- self.used = True
326
- self.generic_visit(node)
327
-
328
- visitor = UsageVisitor()
329
- for st in stmts[start_idx:]:
330
- visitor.visit(st)
331
- if visitor.used:
332
- return True
333
- return False
334
-
335
-
336
324
  def _environment_before(body: list[ast.stmt], index: int, state: _BodyState) -> _RegexEnvironment:
337
325
  prefix = body[:index]
338
326
  local_imports = _regex_imports(prefix)
@@ -2,7 +2,6 @@ from __future__ import annotations
2
2
 
3
3
  import ast
4
4
  from pathlib import PurePosixPath
5
- import re
6
5
  from typing import TYPE_CHECKING, ClassVar, Literal, override
7
6
 
8
7
  from sarj_python_lint.rule_base import (
@@ -24,7 +23,6 @@ if TYPE_CHECKING:
24
23
  from sarj_python_lint._file_context import PythonFileContext
25
24
 
26
25
 
27
- _LOOP_CANDIDATE_RE = re.compile(r"\bwhile\b[^\n:]*\bTrue\b[^\n:]*:")
28
26
  _MIN_BODY_LEN = 3
29
27
  _MAX_REWRITE_COLUMNS = 100
30
28
 
@@ -123,7 +121,8 @@ class PreferWalrusStreamLoop(Rule):
123
121
  path = context.path
124
122
  source = context.source
125
123
  if (
126
- _LOOP_CANDIDATE_RE.search(source) is None
124
+ "while" not in source
125
+ or "True" not in source
127
126
  or "break" not in source
128
127
  or is_test_path(path)
129
128
  or context.generated
@@ -17,7 +17,6 @@ from sarj_python_lint.rule_base import (
17
17
  Severity,
18
18
  is_suppressed,
19
19
  )
20
- from sarj_python_lint.rules._imports import ImportIndex
21
20
  from sarj_python_lint.rules._inert_model_annotation import inert_model_annotation
22
21
 
23
22
 
@@ -25,6 +24,7 @@ if TYPE_CHECKING:
25
24
  from pathlib import Path
26
25
 
27
26
  from sarj_python_lint._file_context import PythonFileContext
27
+ from sarj_python_lint.rules._imports import ImportIndex
28
28
 
29
29
 
30
30
  _MODEL_SOURCES = frozenset({"pydantic", "pydantic.main"})
@@ -98,7 +98,7 @@ class SharedMutablePydanticFactory(Rule):
98
98
  if "default_factory" not in context.symbol_source or context.generated or context.tree is None:
99
99
  return []
100
100
  tree = context.tree
101
- imports = ImportIndex.from_tree(tree)
101
+ imports = context.imports
102
102
  bindings = _stable_bindings(tree)
103
103
  models = {
104
104
  model for model in tree.body if isinstance(model, ast.ClassDef) and _unconfigured_model(model, imports)