sarj-python-lint 1.108.50__tar.gz → 1.108.52__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 (322) hide show
  1. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/PKG-INFO +2 -2
  2. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/pyproject.toml +2 -2
  3. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_rule_descriptors.py +1 -1
  4. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_binding_inventory.py +8 -2
  5. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_closed_helpers.py +1 -1
  6. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_declared_contracts.py +38 -3
  7. sarj_python_lint-1.108.52/src/sarj_python_lint/rules/_fixture_contracts.py +278 -0
  8. sarj_python_lint-1.108.52/src/sarj_python_lint/rules/_pytest_contract_parameters.py +539 -0
  9. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +63 -5
  10. sarj_python_lint-1.108.52/src/sarj_python_lint/rules/prefer_pytest_fixture_contract.py +156 -0
  11. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +2 -2
  12. sarj_python_lint-1.108.50/src/sarj_python_lint/rules/prefer_pytest_fixture_contract.py +0 -213
  13. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/.gitignore +0 -0
  14. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/LICENSE +0 -0
  15. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/README.md +0 -0
  16. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/__init__.py +0 -0
  17. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/__main__.py +0 -0
  18. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_analysis_session.py +0 -0
  19. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_autofix.py +0 -0
  20. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_autofix_aliases.py +0 -0
  21. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_autofix_annotations.py +0 -0
  22. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_autofix_comments.py +0 -0
  23. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_autofix_declared_contracts.py +0 -0
  24. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_autofix_declared_tests.py +0 -0
  25. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_autofix_docs.py +0 -0
  26. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_autofix_enums.py +0 -0
  27. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_autofix_exhaustiveness.py +0 -0
  28. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_autofix_inert.py +0 -0
  29. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_autofix_parameters.py +0 -0
  30. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_autofix_repeated.py +0 -0
  31. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_autofix_security.py +0 -0
  32. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_autofix_sql_projection.py +0 -0
  33. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_autofix_tests.py +0 -0
  34. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_file_context.py +0 -0
  35. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_filesystem.py +0 -0
  36. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_fixes.py +0 -0
  37. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_parallel.py +0 -0
  38. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_prepared_sources.py +0 -0
  39. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_python_target.py +0 -0
  40. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_ratchet_cli.py +0 -0
  41. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_secret_names.py +0 -0
  42. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_source.py +0 -0
  43. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/_version.py +0 -0
  44. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/application_logging.py +0 -0
  45. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/autofix.py +0 -0
  46. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/benchmark.py +0 -0
  47. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/cast_access.py +0 -0
  48. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/interpreter_argv.py +0 -0
  49. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/json_boundary.py +0 -0
  50. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/py.typed +0 -0
  51. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/ratchet.py +0 -0
  52. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rule_base.py +0 -0
  53. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rule_metadata.py +0 -0
  54. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/__init__.py +0 -0
  55. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_annotation_origins.py +0 -0
  56. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
  57. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_ast_index.py +0 -0
  58. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_ast_names.py +0 -0
  59. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_ast_position.py +0 -0
  60. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_async_lifecycle.py +0 -0
  61. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_comment_narration.py +0 -0
  62. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_comments.py +0 -0
  63. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
  64. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_copy_on_write.py +0 -0
  65. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_data_union_discriminator.py +0 -0
  66. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
  67. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_docstrings.py +0 -0
  68. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_exports.py +0 -0
  69. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_fastapi.py +0 -0
  70. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_first_party.py +0 -0
  71. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
  72. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_imports.py +0 -0
  73. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_inert_model_annotation.py +0 -0
  74. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_inherited_contract.py +0 -0
  75. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_local_alias_fix.py +0 -0
  76. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_local_source.py +0 -0
  77. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_logging.py +0 -0
  78. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_loguru.py +0 -0
  79. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_mapping_shape_callbacks.py +0 -0
  80. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_namespace_access.py +0 -0
  81. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_native_namespace_capability.py +0 -0
  82. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_native_object_contracts.py +0 -0
  83. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
  84. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_numeric_proof.py +0 -0
  85. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_opaque_contracts.py +0 -0
  86. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_paths.py +0 -0
  87. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_postgres.py +0 -0
  88. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_postgres_ctas.py +0 -0
  89. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_project_index.py +0 -0
  90. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
  91. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_pydantic_field_contract.py +0 -0
  92. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_pytest.py +0 -0
  93. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_registry.py +0 -0
  94. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_resolved_operation_signature.py +0 -0
  95. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
  96. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_route_shapes.py +0 -0
  97. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_runtime_bindings.py +0 -0
  98. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_runtime_names.py +0 -0
  99. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_runtime_registry.py +0 -0
  100. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_service_http_callbacks.py +0 -0
  101. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_set_fields.py +0 -0
  102. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_sql.py +0 -0
  103. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_sql_aggregate_identity.py +0 -0
  104. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_sql_explain.py +0 -0
  105. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_sql_policy_source.py +0 -0
  106. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_static_json_alias.py +0 -0
  107. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_store_sql.py +0 -0
  108. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_store_writes.py +0 -0
  109. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
  110. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
  111. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_test_composition.py +0 -0
  112. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_test_provenance.py +0 -0
  113. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_transactional_sql.py +0 -0
  114. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/_type_guard_symbols.py +0 -0
  115. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
  116. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/async_executor_shutdown.py +0 -0
  117. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
  118. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/async_subprocess_cancellation_cleanup.py +0 -0
  119. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/cancel_owned_task_without_join.py +0 -0
  120. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
  121. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
  122. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/delete_route_returns_no_content.py +0 -0
  123. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
  124. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
  125. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/duplicate_adjacent_exception_handler.py +0 -0
  126. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/duplicate_closed_pure_helper.py +0 -0
  127. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/duplicate_pytest_fixture_params.py +0 -0
  128. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
  129. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/failed_probe_zero_threshold.py +0 -0
  130. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
  131. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
  132. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
  133. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
  134. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
  135. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
  136. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
  137. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/nan_hidden_by_builtin_min.py +0 -0
  138. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
  139. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
  140. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
  141. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_async_client_in_constructor.py +0 -0
  142. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_async_function_cache.py +0 -0
  143. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_before_validator_input_mutation.py +0 -0
  144. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_blanket_suppression.py +0 -0
  145. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_broad_keyword_capture.py +0 -0
  146. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
  147. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_conflicting_pydantic_alias_validation.py +0 -0
  148. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
  149. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_contradictory_type_guard.py +0 -0
  150. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
  151. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
  152. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_create_verb_in_post_path.py +0 -0
  153. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_custom_control_flow_exception.py +0 -0
  154. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
  155. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_defaulted_environment_setting.py +0 -0
  156. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
  157. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_discarded_tagged_outcome.py +0 -0
  158. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_discarded_validation_result.py +0 -0
  159. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_dual_shape_model_field_reader.py +0 -0
  160. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
  161. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
  162. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_duplicate_field_validator_body.py +0 -0
  163. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_dynamic_builtins.py +0 -0
  164. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_exception_text_in_500_detail.py +0 -0
  165. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
  166. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
  167. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
  168. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
  169. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
  170. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_fixed_sleep_in_loop.py +0 -0
  171. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_folded_bad_request_not_found.py +0 -0
  172. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
  173. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_generic_json_parser.py +0 -0
  174. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
  175. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_hasattr.py +0 -0
  176. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
  177. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_impossible_pydantic_field_bounds.py +0 -0
  178. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
  179. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_input_model_mutation.py +0 -0
  180. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_interpreter_source_arguments.py +0 -0
  181. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
  182. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_invalid_pydantic_bypass.py +0 -0
  183. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_invalid_pydantic_validator_return.py +0 -0
  184. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_loguru_exc_info.py +0 -0
  185. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_loguru_printf_format.py +0 -0
  186. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_mocked_pydantic_value_object.py +0 -0
  187. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_mutating_container_transform.py +0 -0
  188. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_mutating_input_with_result.py +0 -0
  189. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
  190. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
  191. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
  192. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_partial_type_is.py +0 -0
  193. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
  194. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
  195. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
  196. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
  197. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
  198. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_recording_store.py +0 -0
  199. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_redundant_attribute_unpacking.py +0 -0
  200. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
  201. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_redundant_local_alias.py +0 -0
  202. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
  203. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_redundant_sql_alias.py +0 -0
  204. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
  205. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
  206. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
  207. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
  208. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_select_star.py +0 -0
  209. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
  210. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
  211. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_shallow_record_type_guard.py +0 -0
  212. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_shared_mutable_default.py +0 -0
  213. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_slash_collection_root_under_prefix.py +0 -0
  214. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
  215. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
  216. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_sys_path_mutation.py +0 -0
  217. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
  218. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_test_comments.py +0 -0
  219. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_test_method_grafting.py +0 -0
  220. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
  221. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
  222. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_unknown_pydantic_validator_field.py +0 -0
  223. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
  224. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_unused_copy_result.py +0 -0
  225. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +0 -0
  226. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
  227. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
  228. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
  229. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/no_work_verb_get_route.py +0 -0
  230. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
  231. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
  232. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
  233. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_application_model_joins.py +0 -0
  234. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +0 -0
  235. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_bulk_upsert.py +0 -0
  236. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
  237. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
  238. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
  239. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_declarative_batch_validation.py +0 -0
  240. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_direct_import_module.py +0 -0
  241. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_discriminated_model_union.py +0 -0
  242. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
  243. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_grouped_settings.py +0 -0
  244. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
  245. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
  246. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
  247. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
  248. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
  249. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
  250. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
  251. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
  252. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
  253. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
  254. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
  255. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_native_string_check.py +0 -0
  256. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
  257. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_optional_composite.py +0 -0
  258. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
  259. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_precise_object_contract.py +0 -0
  260. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_psycopg_executemany.py +0 -0
  261. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
  262. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_pydantic_model_assertion.py +0 -0
  263. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_pytest_dependency_fixtures.py +0 -0
  264. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +0 -0
  265. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
  266. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_required_constructor_parameters.py +0 -0
  267. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_runtime_validation.py +0 -0
  268. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
  269. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
  270. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
  271. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
  272. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
  273. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_typed_cli.py +0 -0
  274. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_typed_mapping_get.py +0 -0
  275. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_typed_settings_field.py +0 -0
  276. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
  277. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
  278. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
  279. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
  280. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
  281. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/pytest_fixture_returns_closed_resource.py +0 -0
  282. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
  283. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
  284. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
  285. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/redundant_test_constructor_forwarder.py +0 -0
  286. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
  287. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
  288. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
  289. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/repeated_unimplemented_test_contract.py +0 -0
  290. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/require_constrained_api_integer.py +0 -0
  291. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/require_exp_on_jwt_decode.py +0 -0
  292. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
  293. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
  294. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
  295. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/require_injectable_retry_sleep.py +0 -0
  296. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
  297. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
  298. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
  299. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/require_precise_factory_signature.py +0 -0
  300. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
  301. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
  302. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/require_pydantic_for_mapping_shape.py +0 -0
  303. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
  304. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
  305. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
  306. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/service_singleton_delegates_to_bulk.py +0 -0
  307. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
  308. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/stepdown.py +0 -0
  309. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/store_field_update_reuses_upsert.py +0 -0
  310. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
  311. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/store_insert_requires_explicit_conflict_policy.py +0 -0
  312. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
  313. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/store_mutation_command_fanout.py +0 -0
  314. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
  315. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/test_without_explicit_oracle.py +0 -0
  316. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
  317. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
  318. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
  319. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
  320. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
  321. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/rules/unused_test_factory_option.py +0 -0
  322. {sarj_python_lint-1.108.50 → sarj_python_lint-1.108.52}/src/sarj_python_lint/suppression_policy.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sarj-python-lint
3
- Version: 1.108.50
3
+ Version: 1.108.52
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/
@@ -19,7 +19,7 @@ Classifier: Topic :: Software Development :: Quality Assurance
19
19
  Requires-Python: >=3.14
20
20
  Requires-Dist: packaging==26.3
21
21
  Requires-Dist: ruff>=0.17.2
22
- Requires-Dist: sarj-rule-contracts==0.6.1
22
+ Requires-Dist: sarj-rule-contracts==0.6.2
23
23
  Requires-Dist: sqlglot==30.24.0
24
24
  Requires-Dist: typer==0.27.3
25
25
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sarj-python-lint"
3
- version = "1.108.50"
3
+ version = "1.108.52"
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" }]
@@ -15,7 +15,7 @@ classifiers = [
15
15
  "Programming Language :: Python :: 3.14",
16
16
  "Topic :: Software Development :: Quality Assurance",
17
17
  ]
18
- dependencies = ["sarj-rule-contracts==0.6.1", "packaging==26.3", "ruff>=0.17.2", "sqlglot==30.24.0", "typer==0.27.3"]
18
+ dependencies = ["sarj-rule-contracts==0.6.2", "packaging==26.3", "ruff>=0.17.2", "sqlglot==30.24.0", "typer==0.27.3"]
19
19
 
20
20
  [project.scripts]
21
21
  sarj-python-lint = "sarj_python_lint.__main__:main"
@@ -1507,7 +1507,7 @@ DESCRIPTORS: tuple[RuleDescriptor, ...] = (
1507
1507
  module="sarj_python_lint.rules.prefer_pytest_fixture_contract",
1508
1508
  class_name="PreferPytestFixtureContract",
1509
1509
  code="SARJ550",
1510
- description="Expose an existing abstract service contract from pytest fixtures.",
1510
+ description="Expose existing abstract contracts from pytest fixtures and injected parameters.",
1511
1511
  aliases=(),
1512
1512
  enabled_by_default=True,
1513
1513
  ),
@@ -46,7 +46,7 @@ class BindingInventory:
46
46
  for node in context.nodes(ast.AST):
47
47
  if isinstance(node, ast.Name) and isinstance(node.ctx, ast.Load):
48
48
  reads[node.id].append(node)
49
- for name in _bound_names(node):
49
+ for name in binding_names(node):
50
50
  bindings[_binding_scope(parents, node)][name].append(node)
51
51
  wildcard |= name == "*"
52
52
  if isinstance(node, ast.Global | ast.Nonlocal):
@@ -109,7 +109,7 @@ def _binding_scope(parents: Mapping[ast.AST, ast.AST], node: ast.AST) -> ast.AST
109
109
  return scope
110
110
 
111
111
 
112
- def _bound_names(node: ast.AST) -> tuple[str, ...]:
112
+ def binding_names(node: ast.AST) -> tuple[str, ...]:
113
113
  match node:
114
114
  case ast.Name(id=name, ctx=ast.Store() | ast.Del()) | ast.arg(arg=name):
115
115
  return (name,)
@@ -129,3 +129,9 @@ def _bound_names(node: ast.AST) -> tuple[str, ...]:
129
129
  return tuple(names)
130
130
  case _:
131
131
  return ()
132
+
133
+
134
+ def scope_binding_names(statement: ast.AST) -> frozenset[str]:
135
+ nodes = tuple(ast.walk(statement))
136
+ parents = {child: node for node in nodes for child in ast.iter_child_nodes(node)}
137
+ return frozenset(name for node in nodes if _binding_scope(parents, node) is None for name in binding_names(node))
@@ -93,7 +93,7 @@ def direct_call(reference: ast.Name, context: PythonFileContext) -> ast.Call | N
93
93
  return parent
94
94
 
95
95
 
96
- def call_matches(function: ast.FunctionDef, call: ast.Call) -> bool:
96
+ def call_matches(function: ast.FunctionDef | ast.AsyncFunctionDef, call: ast.Call) -> bool:
97
97
  positional = [*function.args.posonlyargs, *function.args.args]
98
98
  keywords = {arg.arg for arg in (*function.args.args, *function.args.kwonlyargs)}
99
99
  required = {arg.arg for arg in positional[: len(positional) - len(function.args.defaults)]}
@@ -5,6 +5,7 @@ from dataclasses import dataclass
5
5
  from typing import TYPE_CHECKING
6
6
 
7
7
  from sarj_python_lint.rules._annotation_semantics import AnnotationSemantics
8
+ from sarj_python_lint.rules._binding_inventory import binding_names, scope_binding_names
8
9
  from sarj_python_lint.rules._imports import ImportIndex
9
10
  from sarj_python_lint.rules._project_index import ProjectIndexSet, SourceUnit, SymbolRef
10
11
 
@@ -21,6 +22,12 @@ _MAX_DEPTH = 8
21
22
  _TYPING_SOURCES = frozenset({"typing", "typing_extensions"})
22
23
 
23
24
 
25
+ def _attribute_root(node: ast.expr) -> str | None:
26
+ while isinstance(node, ast.Attribute):
27
+ node = node.value
28
+ return node.id if isinstance(node, ast.Name) else None
29
+
30
+
24
31
  @dataclass(frozen=True)
25
32
  class DeclaredClass:
26
33
  unit: SourceUnit
@@ -53,6 +60,7 @@ class DeclaredContracts:
53
60
  self.context = context
54
61
  self._field_cache: dict[tuple[ast.ClassDef, bool], dict[str, ast.AnnAssign]] = {}
55
62
  self._module_annotations: dict[Path, AnnotationSemantics] = {}
63
+ self._scope_names: dict[ast.AST, frozenset[str]] = {}
56
64
  self.project = context.session.project or ProjectIndexSet.single(context.path, context.source)
57
65
  self.unit = self.project.unit(context.path)
58
66
  if self.unit is not None and self.unit.tree is not context.tree:
@@ -85,29 +93,48 @@ class DeclaredContracts:
85
93
  return DeclaredClass(source, declaration) if declaration is not None else None
86
94
 
87
95
  def _lookup_allowed(self, expression: ast.expr, owner: SourceUnit, at: ast.AST | None) -> bool:
88
- if owner is not self.unit or (at or expression) not in self.context.parents:
89
- return True
90
96
  root = expression
91
97
  while isinstance(root, ast.Attribute):
92
98
  root = root.value
93
99
  if not isinstance(root, ast.Name):
94
100
  return True
101
+ if owner is not self.unit:
102
+ return self._foreign_lookup_allowed(owner, root.id)
103
+ if (at or expression) not in self.context.parents:
104
+ return True
95
105
  binding = self.context.static_resource_provenance.binding(root.id, at or expression)
96
106
  return (
97
107
  isinstance(binding, ast.alias | ast.ClassDef)
98
108
  and root.id not in self.context.static_resource_provenance.mutated
99
109
  )
100
110
 
111
+ def _foreign_lookup_allowed(self, owner: SourceUnit, name: str) -> bool:
112
+ if owner.tree is None:
113
+ return False
114
+ if name not in owner.imports:
115
+ return True
116
+ imports = self._module_semantics(owner).imports
117
+ if name in imports.shadowed_names:
118
+ return False
119
+ return not any(
120
+ isinstance(node, ast.Attribute) and not isinstance(node.ctx, ast.Load) and _attribute_root(node) == name
121
+ for node in ast.walk(owner.tree)
122
+ )
123
+
101
124
  def _stable_declaration(self, source: SourceUnit, name: str) -> ast.ClassDef | None:
102
125
  if source.tree is None:
103
126
  return None
104
127
  declarations = [node for node in source.tree.body if isinstance(node, ast.ClassDef) and node.name == name]
105
128
  if len(declarations) != 1 or declarations[0].keywords:
106
129
  return None
130
+ if any(
131
+ isinstance(node, ast.FunctionDef | ast.AsyncFunctionDef) and node.name == name for node in source.tree.body
132
+ ):
133
+ return None
107
134
  if not self._identity_decorators(source, declarations[0]):
108
135
  return None
109
136
  if any(
110
- isinstance(node, ast.Name) and node.id == name and isinstance(node.ctx, ast.Store | ast.Del)
137
+ name in binding_names(node)
111
138
  for statement in source.tree.body
112
139
  if not isinstance(statement, ast.ClassDef | ast.FunctionDef | ast.AsyncFunctionDef)
113
140
  for node in ast.walk(statement)
@@ -175,6 +202,14 @@ class DeclaredContracts:
175
202
  self._module_annotations[unit.path] = semantics
176
203
  return semantics
177
204
 
205
+ def imports_for(self, unit: SourceUnit) -> ImportIndex:
206
+ return self._module_semantics(unit).imports
207
+
208
+ def bound_names(self, statement: ast.AST) -> frozenset[str]:
209
+ if statement not in self._scope_names:
210
+ self._scope_names[statement] = scope_binding_names(statement)
211
+ return self._scope_names[statement]
212
+
178
213
  def annotation(self, expression: ast.expr, unit: SourceUnit | None = None) -> DeclaredClass | None:
179
214
  semantics = self.context.annotation_semantics
180
215
  if unit is not None and unit is not self.unit and unit.tree is not None:
@@ -0,0 +1,278 @@
1
+ from __future__ import annotations
2
+
3
+ import ast
4
+ from dataclasses import dataclass
5
+ from typing import TYPE_CHECKING
6
+
7
+ from sarj_python_lint.rules._binding_inventory import scope_binding_names
8
+ from sarj_python_lint.rules._declared_contracts import DeclaredClass
9
+ from sarj_python_lint.rules._project_index import SourceUnit, SymbolRef
10
+ from sarj_python_lint.rules._resolved_operation_signature import resolved_operation_signature
11
+ from sarj_python_lint.rules.pytest_fixture_returns_bare_tuple import fixture_yields
12
+
13
+
14
+ if TYPE_CHECKING:
15
+ from sarj_python_lint.rules._declared_contracts import DeclaredContracts
16
+ from sarj_python_lint.rules._imports import ImportIndex
17
+
18
+
19
+ PORT_BASES = frozenset({"abc.ABC", "typing.Protocol", "typing_extensions.Protocol"})
20
+ MAX_DEPTH = 8
21
+ _METHOD_DECORATORS = frozenset({"abc.abstractmethod", "typing.override", "typing_extensions.override"})
22
+ CONSTRUCTION_HOOKS = frozenset({"__new__", "__init_subclass__"})
23
+ _MEMBER_HOOKS = frozenset({"__getattribute__", "__getattr__", "__init_subclass__"})
24
+
25
+
26
+ @dataclass(frozen=True)
27
+ class DeclaredMethod:
28
+ declaration: ast.FunctionDef | ast.AsyncFunctionDef
29
+ owner: DeclaredClass
30
+
31
+
32
+ def abstract_contract(model: DeclaredClass, contracts: DeclaredContracts) -> bool:
33
+ if model.unit.tree is None:
34
+ return False
35
+ imports = contracts.imports_for(model.unit)
36
+ return any(
37
+ imports.resolved_qualified_name(base) in {"typing.Protocol", "typing_extensions.Protocol"}
38
+ for base in model.declaration.bases
39
+ ) or bool(_abstract_members(model, contracts))
40
+
41
+
42
+ def _abstract_members(
43
+ model: DeclaredClass,
44
+ contracts: DeclaredContracts,
45
+ seen: frozenset[ast.ClassDef] = frozenset(),
46
+ *,
47
+ cache: dict[tuple[ast.ClassDef, int], frozenset[str]] | None = None,
48
+ ) -> frozenset[str]:
49
+ if model.unit.tree is None or model.declaration in seen or len(seen) >= MAX_DEPTH:
50
+ return frozenset()
51
+ memo = {} if cache is None else cache
52
+ key = model.declaration, len(seen)
53
+ if key in memo:
54
+ return memo[key]
55
+ imports = contracts.imports_for(model.unit)
56
+ pending: set[str] = set()
57
+ for base in model.declaration.bases:
58
+ parent = contracts.class_type(base, model.unit)
59
+ if parent is not None:
60
+ pending.update(_abstract_members(parent, contracts, seen | {model.declaration}, cache=memo))
61
+ for member in model.declaration.body:
62
+ if isinstance(member, ast.FunctionDef | ast.AsyncFunctionDef):
63
+ if any(
64
+ imports.resolves(decorator, sources=frozenset({"abc"}), symbol="abstractmethod")
65
+ for decorator in member.decorator_list
66
+ ):
67
+ pending.add(member.name)
68
+ else:
69
+ pending.discard(member.name)
70
+ result = frozenset(pending)
71
+ memo[key] = result
72
+ return result
73
+
74
+
75
+ def abstract_ancestors(model: DeclaredClass, contracts: DeclaredContracts) -> tuple[DeclaredClass, ...]:
76
+ pending = [(model, 0)]
77
+ seen: set[ast.ClassDef] = set()
78
+ found: dict[ast.ClassDef, DeclaredClass] = {}
79
+ checked: list[DeclaredClass] = []
80
+ while pending:
81
+ current, depth = pending.pop()
82
+ if depth >= MAX_DEPTH:
83
+ return ()
84
+ if current.declaration in seen:
85
+ continue
86
+ seen.add(current.declaration)
87
+ checked.append(current)
88
+ for base in current.declaration.bases:
89
+ owner = contracts.class_type(base, current.unit)
90
+ if owner is None:
91
+ continue
92
+ if abstract_contract(owner, contracts) and contracts.inherits(owner, PORT_BASES):
93
+ found[owner.declaration] = owner
94
+ else:
95
+ pending.append((owner, depth + 1))
96
+ candidates = tuple(found.values())
97
+ if len(candidates) != 1:
98
+ return candidates
99
+ return candidates if all(class_identity_stable(current, contracts) for current in checked) else ()
100
+
101
+
102
+ def contract_accepts(model: DeclaredClass, target: DeclaredClass, contracts: DeclaredContracts) -> bool:
103
+ pending = [(model, 0)]
104
+ seen: set[ast.ClassDef] = set()
105
+ while pending:
106
+ current, depth = pending.pop()
107
+ if current.declaration is target.declaration:
108
+ return True
109
+ if current.declaration in seen or depth >= MAX_DEPTH:
110
+ continue
111
+ seen.add(current.declaration)
112
+ pending.extend(
113
+ (parent, depth + 1)
114
+ for base in current.declaration.bases
115
+ if (parent := contracts.class_type(base, current.unit)) is not None
116
+ )
117
+ return False
118
+
119
+
120
+ def has_class_hook(
121
+ model: DeclaredClass,
122
+ contracts: DeclaredContracts,
123
+ names: frozenset[str],
124
+ ) -> bool:
125
+ pending = [(model, 0)]
126
+ seen: set[ast.ClassDef] = set()
127
+ while pending:
128
+ current, depth = pending.pop()
129
+ if depth >= MAX_DEPTH:
130
+ return True
131
+ if current.declaration in seen:
132
+ continue
133
+ seen.add(current.declaration)
134
+ if _declares_hook(current, names):
135
+ return True
136
+ parents = _hook_parents(current, contracts)
137
+ if parents is None:
138
+ return True
139
+ pending.extend((parent, depth + 1) for parent in parents)
140
+ return False
141
+
142
+
143
+ def _declares_hook(model: DeclaredClass, names: frozenset[str]) -> bool:
144
+ return any(
145
+ (isinstance(member, ast.FunctionDef | ast.AsyncFunctionDef) and member.name in names)
146
+ or any(_class_member_replaced(member, name) for name in names)
147
+ for member in model.declaration.body
148
+ )
149
+
150
+
151
+ def _hook_parents(model: DeclaredClass, contracts: DeclaredContracts) -> tuple[DeclaredClass, ...] | None:
152
+ imports = contracts.imports_for(model.unit) if model.unit.tree is not None else None
153
+ parents: list[DeclaredClass] = []
154
+ for base in model.declaration.bases:
155
+ parent = contracts.class_type(base, model.unit)
156
+ if parent is not None:
157
+ parents.append(parent)
158
+ elif imports is None or imports.resolved_qualified_name(base) not in PORT_BASES:
159
+ return None
160
+ return tuple(parents)
161
+
162
+
163
+ def method_definition(
164
+ model: DeclaredClass,
165
+ name: str,
166
+ contracts: DeclaredContracts,
167
+ seen: frozenset[ast.ClassDef] = frozenset(),
168
+ ) -> DeclaredMethod | None:
169
+ if (
170
+ model.declaration in seen
171
+ or len(seen) >= MAX_DEPTH
172
+ or model.declaration.type_params
173
+ or not class_identity_stable(model, contracts)
174
+ ):
175
+ return None
176
+ if _method_replaced(model.declaration, name):
177
+ return None
178
+ definitions = [
179
+ member
180
+ for member in model.declaration.body
181
+ if isinstance(member, ast.FunctionDef | ast.AsyncFunctionDef) and member.name == name
182
+ ]
183
+ if definitions:
184
+ return DeclaredMethod(definitions[0], model) if len(definitions) == 1 else None
185
+ if len(model.declaration.bases) != 1:
186
+ return None
187
+ inherited = [
188
+ result
189
+ for base in model.declaration.bases
190
+ if (parent := contracts.class_type(base, model.unit)) is not None
191
+ and (result := method_definition(parent, name, contracts, seen | {model.declaration})) is not None
192
+ ]
193
+ return inherited[0] if len(inherited) == 1 else None
194
+
195
+
196
+ def _method_replaced(declaration: ast.ClassDef, name: str) -> bool:
197
+ instance_write = any(
198
+ isinstance(node, ast.Attribute) and node.attr == name and isinstance(node.ctx, ast.Store | ast.Del)
199
+ for node in ast.walk(declaration)
200
+ )
201
+ return instance_write or any(_class_member_replaced(member, name) for member in declaration.body)
202
+
203
+
204
+ def _class_member_replaced(member: ast.AST, name: str) -> bool:
205
+ match member:
206
+ case ast.FunctionDef() | ast.AsyncFunctionDef():
207
+ return False
208
+ case ast.ClassDef(name=bound):
209
+ return bound == name
210
+ case _:
211
+ pass
212
+ return name in scope_binding_names(member)
213
+
214
+
215
+ def compatible_operation(
216
+ implementation: DeclaredClass, contract: DeclaredClass, name: str, contracts: DeclaredContracts
217
+ ) -> bool:
218
+ if name.startswith("_") or has_class_hook(implementation, contracts, _MEMBER_HOOKS):
219
+ return False
220
+ concrete = method_definition(implementation, name, contracts)
221
+ abstract = method_definition(contract, name, contracts)
222
+ if concrete is None or abstract is None:
223
+ return False
224
+ if isinstance(concrete.declaration, ast.AsyncFunctionDef) and fixture_yields(
225
+ concrete.declaration
226
+ ) != fixture_yields(abstract.declaration):
227
+ return False
228
+ concrete_signature = _operation_signature(concrete, contracts)
229
+ return concrete_signature is not None and concrete_signature == _operation_signature(abstract, contracts)
230
+
231
+
232
+ def class_identity_stable(model: DeclaredClass, contracts: DeclaredContracts) -> bool:
233
+ module = model.unit.module
234
+ return module is not None and not contracts.project.nominal_membership_is_dynamic(
235
+ SymbolRef(module, model.declaration.name)
236
+ )
237
+
238
+
239
+ def _operation_signature(definition: DeclaredMethod, contracts: DeclaredContracts) -> str | None:
240
+ method, unit = definition.declaration, definition.owner.unit
241
+ if unit.tree is None:
242
+ return None
243
+ imports = contracts.imports_for(unit)
244
+ if any(imports.resolved_qualified_name(decorator) not in _METHOD_DECORATORS for decorator in method.decorator_list):
245
+ return None
246
+ annotations = [
247
+ method.returns,
248
+ *(argument.annotation for argument in (*method.args.posonlyargs, *method.args.args, *method.args.kwonlyargs)),
249
+ ]
250
+ shadowed = frozenset(name for member in definition.owner.declaration.body for name in contracts.bound_names(member))
251
+ if any(
252
+ _opaque_annotation(annotation, unit, contracts, imports, shadowed)
253
+ for annotation in annotations
254
+ if annotation is not None
255
+ ):
256
+ return None
257
+ return resolved_operation_signature(method, unit, imports)
258
+
259
+
260
+ def _opaque_annotation(
261
+ annotation: ast.expr, unit: SourceUnit, contracts: DeclaredContracts, imports: ImportIndex, shadowed: frozenset[str]
262
+ ) -> bool:
263
+ for node in ast.walk(annotation):
264
+ if not isinstance(node, ast.Name | ast.Attribute):
265
+ continue
266
+ if isinstance(node, ast.Name) and node.id in shadowed:
267
+ return True
268
+ if imports.resolved_qualified_name(node) in {"typing.Self", "typing_extensions.Self"}:
269
+ return True
270
+ if _source_alias_annotation(node, unit, contracts):
271
+ return True
272
+ return False
273
+
274
+
275
+ def _source_alias_annotation(node: ast.Name | ast.Attribute, unit: SourceUnit, contracts: DeclaredContracts) -> bool:
276
+ symbol = contracts.project.resolve(unit, node)
277
+ source = contracts.project.source_unit(symbol.module) if symbol is not None else None
278
+ return source is not None and source is not unit and contracts.class_type(node, unit) is None