sarj-python-lint 1.15.0__tar.gz → 1.15.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/PKG-INFO +1 -1
  2. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/pyproject.toml +1 -1
  3. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_sql.py +11 -0
  4. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +77 -9
  5. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/.gitignore +0 -0
  6. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/LICENSE +0 -0
  7. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/README.md +0 -0
  8. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/__init__.py +0 -0
  9. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/__main__.py +0 -0
  10. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/_analysis_session.py +0 -0
  11. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/_file_context.py +0 -0
  12. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/_filesystem.py +0 -0
  13. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/_python_target.py +0 -0
  14. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/_ratchet_cli.py +0 -0
  15. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/_secret_names.py +0 -0
  16. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/_version.py +0 -0
  17. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/benchmark.py +0 -0
  18. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/json_boundary.py +0 -0
  19. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/py.typed +0 -0
  20. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/ratchet.py +0 -0
  21. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rule_base.py +0 -0
  22. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/__init__.py +0 -0
  23. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
  24. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_ast_index.py +0 -0
  25. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_ast_position.py +0 -0
  26. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_comments.py +0 -0
  27. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
  28. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
  29. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_docstrings.py +0 -0
  30. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_fastapi.py +0 -0
  31. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_first_party.py +0 -0
  32. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
  33. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_imports.py +0 -0
  34. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_local_source.py +0 -0
  35. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_logging.py +0 -0
  36. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
  37. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_paths.py +0 -0
  38. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_project_index.py +0 -0
  39. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
  40. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_pytest.py +0 -0
  41. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_registry.py +0 -0
  42. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
  43. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_set_fields.py +0 -0
  44. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
  45. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
  46. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/_test_composition.py +0 -0
  47. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
  48. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
  49. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
  50. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
  51. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/discourage_nullable_constructor_parameters.py +0 -0
  52. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
  53. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
  54. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
  55. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
  56. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
  57. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
  58. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
  59. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
  60. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
  61. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
  62. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
  63. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
  64. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
  65. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
  66. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
  67. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
  68. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
  69. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
  70. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
  71. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
  72. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
  73. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
  74. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
  75. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
  76. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
  77. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
  78. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
  79. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
  80. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
  81. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
  82. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
  83. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
  84. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
  85. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
  86. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
  87. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
  88. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
  89. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
  90. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
  91. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
  92. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
  93. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
  94. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
  95. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
  96. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
  97. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_select_star.py +0 -0
  98. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
  99. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
  100. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
  101. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
  102. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
  103. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
  104. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
  105. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
  106. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +0 -0
  107. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
  108. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
  109. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
  110. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
  111. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
  112. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
  113. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +0 -0
  114. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
  115. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
  116. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
  117. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
  118. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
  119. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
  120. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
  121. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
  122. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
  123. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
  124. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
  125. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
  126. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
  127. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
  128. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
  129. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
  130. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
  131. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
  132. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
  133. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
  134. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
  135. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
  136. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
  137. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
  138. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
  139. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
  140. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
  141. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
  142. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
  143. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
  144. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
  145. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
  146. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
  147. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
  148. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
  149. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
  150. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
  151. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
  152. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
  153. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
  154. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
  155. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
  156. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
  157. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/require_precise_factory_signature.py +0 -0
  158. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
  159. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
  160. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
  161. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
  162. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
  163. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
  164. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/stepdown.py +0 -0
  165. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
  166. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
  167. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
  168. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
  169. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
  170. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
  171. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
  172. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
  173. {sarj_python_lint-1.15.0 → sarj_python_lint-1.15.2}/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.15.0
3
+ Version: 1.15.2
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.15.0"
3
+ version = "1.15.2"
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" }]
@@ -64,8 +64,17 @@ def strip_sql_noise(
64
64
 
65
65
  def _quoted_sql_end(text: str, start: int) -> int:
66
66
  quote = text[start]
67
+ escape_string = (
68
+ quote == "'"
69
+ and start > 0
70
+ and text[start - 1] in {"E", "e"}
71
+ and (start == 1 or not (text[start - 2].isalnum() or text[start - 2] in {"_", "$"}))
72
+ )
67
73
  i = start + 1
68
74
  while i < len(text):
75
+ if escape_string and text[i] == "\\" and i + 1 < len(text):
76
+ i += 2
77
+ continue
69
78
  if text[i] != quote:
70
79
  i += 1
71
80
  continue
@@ -107,6 +116,8 @@ def _block_comment_end(text: str, start: int) -> int:
107
116
 
108
117
 
109
118
  def _dollar_quote_end(text: str, start: int) -> int | None:
119
+ if start > 0 and (text[start - 1].isalnum() or text[start - 1] in {"_", "$"}):
120
+ return None
110
121
  delimiter_end = text.find("$", start + 1)
111
122
  if delimiter_end == -1:
112
123
  return None
@@ -118,13 +118,15 @@ class PreferPytestFixtureInjection(Rule):
118
118
  ):
119
119
  return []
120
120
  tree = context.tree
121
+ helpers = _resource_helpers(context)
122
+ if not helpers:
123
+ return []
121
124
  module_bindings = _scope_bindings(tree)
122
125
  if "__test__" in module_bindings or any(
123
126
  isinstance(node, ast.Attribute) and node.attr == "__test__" and isinstance(node.ctx, (ast.Store, ast.Del))
124
127
  for node in ast.walk(tree)
125
128
  ):
126
129
  return []
127
- helpers = _resource_helpers(context)
128
130
  diagnostics: list[Diagnostic] = []
129
131
  for statement in tree.body:
130
132
  if (
@@ -156,9 +158,12 @@ def _resource_helpers(context: PythonFileContext) -> frozenset[str]:
156
158
  tree = context.tree
157
159
  if tree is None:
158
160
  return frozenset()
161
+ references = tuple(_helper_imports(tree))
162
+ if not references:
163
+ return frozenset()
159
164
  bindings = _scope_bindings(tree)
160
165
  helpers: set[str] = set()
161
- for reference in _helper_imports(tree):
166
+ for reference in references:
162
167
  if bindings[reference.local] != 1 or _root_mutated(tree, reference.local):
163
168
  continue
164
169
  target = context.session.local_source.resolve_module(
@@ -175,15 +180,19 @@ def _resource_helpers(context: PythonFileContext) -> frozenset[str]:
175
180
 
176
181
 
177
182
  def _helper_imports(tree: ast.Module) -> Iterator[_HelperImport]:
178
- if any(isinstance(node, ast.ImportFrom) and any(alias.name == "*" for alias in node.names) for node in tree.body):
179
- return
183
+ candidates: list[_HelperImport] = []
180
184
  for statement in tree.body:
181
- if not isinstance(statement, ast.ImportFrom) or not statement.module:
185
+ if not isinstance(statement, ast.ImportFrom):
182
186
  continue
183
- if statement.module.rsplit(".", 1)[-1] != "conftest":
187
+ module = statement.module
188
+ if module is None or module.rsplit(".", 1)[-1] != "conftest":
184
189
  continue
185
- for alias in statement.names:
186
- yield _HelperImport(alias.asname or alias.name, alias.name, statement.module, statement.level)
190
+ candidates.extend(
191
+ _HelperImport(alias.asname or alias.name, alias.name, module, statement.level) for alias in statement.names
192
+ )
193
+ if not candidates or _has_wildcard(tree):
194
+ return
195
+ yield from candidates
187
196
 
188
197
 
189
198
  def _is_resource_helper(module: LocalModule, symbol: str) -> bool:
@@ -261,7 +270,25 @@ def _assigned_dependency_call(
261
270
  def _pytest_mark(context: PythonFileContext, decorator: ast.expr) -> bool:
262
271
  target = decorator.func if isinstance(decorator, ast.Call) else decorator
263
272
  qualified = context.module_imports.resolved_qualified_name(target)
264
- return qualified is not None and qualified.startswith("pytest.mark.")
273
+ tree = context.tree
274
+ root = _root_name(target)
275
+ if (
276
+ qualified is None
277
+ or not qualified.startswith("pytest.mark.")
278
+ or tree is None
279
+ or root is None
280
+ or _scope_bindings(tree)[root] != 1
281
+ ):
282
+ return False
283
+ for node in ast.walk(tree):
284
+ if not isinstance(node, (ast.Attribute, ast.Subscript)) or not isinstance(node.ctx, (ast.Store, ast.Del)):
285
+ continue
286
+ if isinstance(node, ast.Subscript) and _root_name(node.value) == root:
287
+ return False
288
+ changed = context.module_imports.resolved_qualified_name(node)
289
+ if changed is not None and (qualified == changed or qualified.startswith(f"{changed}.")):
290
+ return False
291
+ return True
265
292
 
266
293
 
267
294
  def _unshadowed_consumer(context: PythonFileContext, call: ast.Call, bindings: Counter[str]) -> bool:
@@ -338,15 +365,46 @@ def _scope_bindings(scope: ast.Module | Function) -> Counter[str]:
338
365
  names.update(arg.arg for arg in (arguments.vararg, arguments.kwarg) if arg is not None)
339
366
  for statement in scope.body:
340
367
  _collect_bindings(statement, names)
368
+ if isinstance(scope, ast.Module):
369
+ names.update(_global_writes(scope))
341
370
  return names
342
371
 
343
372
 
373
+ def _global_writes(tree: ast.Module) -> Counter[str]:
374
+ if not any(isinstance(node, ast.Global) for node in ast.walk(tree)):
375
+ return Counter()
376
+ writes: Counter[str] = Counter()
377
+ for node in ast.walk(tree):
378
+ if not isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
379
+ continue
380
+ names: Counter[str] = Counter()
381
+ declarations: set[str] = set()
382
+ for statement in node.body:
383
+ _collect_bindings(statement, names)
384
+ declarations.update(_global_names(statement))
385
+ writes.update(dict.fromkeys(declarations & names.keys(), 2))
386
+ return writes
387
+
388
+
389
+ def _global_names(node: ast.AST) -> Iterator[str]:
390
+ if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef, ast.Lambda)):
391
+ return
392
+ if isinstance(node, ast.Global):
393
+ yield from node.names
394
+ for child in ast.iter_child_nodes(node):
395
+ yield from _global_names(child)
396
+
397
+
344
398
  def _collect_bindings(node: ast.AST, names: Counter[str]) -> None:
345
399
  match node:
346
400
  case ast.FunctionDef(name=name) | ast.AsyncFunctionDef(name=name) | ast.ClassDef(name=name):
347
401
  names[name] += 1
402
+ for expression in _definition_expressions(node):
403
+ _collect_bindings(expression, names)
348
404
  return
349
405
  case ast.Lambda():
406
+ for expression in _definition_expressions(node):
407
+ _collect_bindings(expression, names)
350
408
  return
351
409
  case ast.Import(names=aliases) | ast.ImportFrom(names=aliases):
352
410
  names.update(alias.asname or alias.name.partition(".")[0] for alias in aliases)
@@ -369,6 +427,16 @@ def _collect_bindings(node: ast.AST, names: Counter[str]) -> None:
369
427
  _collect_bindings(child, names)
370
428
 
371
429
 
430
+ def _definition_expressions(node: ast.FunctionDef | ast.AsyncFunctionDef | ast.ClassDef | ast.Lambda) -> list[ast.AST]:
431
+ if isinstance(node, ast.ClassDef):
432
+ return [*node.decorator_list, *node.bases, *node.keywords]
433
+ defaults: list[ast.AST] = [
434
+ *node.args.defaults,
435
+ *(default for default in node.args.kw_defaults if default is not None),
436
+ ]
437
+ return defaults if isinstance(node, ast.Lambda) else [*node.decorator_list, *defaults]
438
+
439
+
372
440
  def _has_wildcard(tree: ast.Module) -> bool:
373
441
  return any(
374
442
  isinstance(node, ast.ImportFrom) and any(alias.name == "*" for alias in node.names) for node in ast.walk(tree)