sarj-python-lint 1.16.2__tar.gz → 1.16.3__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 (174) hide show
  1. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/PKG-INFO +1 -1
  2. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/pyproject.toml +1 -1
  3. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/unused_test_factory_option.py +124 -11
  4. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/.gitignore +0 -0
  5. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/LICENSE +0 -0
  6. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/README.md +0 -0
  7. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/__init__.py +0 -0
  8. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/__main__.py +0 -0
  9. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/_analysis_session.py +0 -0
  10. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/_file_context.py +0 -0
  11. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/_filesystem.py +0 -0
  12. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/_python_target.py +0 -0
  13. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/_ratchet_cli.py +0 -0
  14. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/_secret_names.py +0 -0
  15. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/_version.py +0 -0
  16. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/benchmark.py +0 -0
  17. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/json_boundary.py +0 -0
  18. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/py.typed +0 -0
  19. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/ratchet.py +0 -0
  20. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rule_base.py +0 -0
  21. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/__init__.py +0 -0
  22. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
  23. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_ast_index.py +0 -0
  24. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_ast_position.py +0 -0
  25. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_comments.py +0 -0
  26. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
  27. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
  28. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_docstrings.py +0 -0
  29. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_fastapi.py +0 -0
  30. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_first_party.py +0 -0
  31. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
  32. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_imports.py +0 -0
  33. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_local_source.py +0 -0
  34. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_logging.py +0 -0
  35. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
  36. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_paths.py +0 -0
  37. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_project_index.py +0 -0
  38. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
  39. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_pytest.py +0 -0
  40. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_registry.py +0 -0
  41. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
  42. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_set_fields.py +0 -0
  43. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_sql.py +0 -0
  44. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
  45. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
  46. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/_test_composition.py +0 -0
  47. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
  48. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
  49. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
  50. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
  51. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/discourage_nullable_constructor_parameters.py +0 -0
  52. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
  53. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
  54. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
  55. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
  56. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
  57. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
  58. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
  59. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
  60. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
  61. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
  62. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
  63. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
  64. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
  65. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_broad_keyword_capture.py +0 -0
  66. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
  67. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
  68. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
  69. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
  70. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
  71. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
  72. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
  73. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
  74. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
  75. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
  76. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
  77. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
  78. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
  79. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
  80. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
  81. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
  82. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
  83. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
  84. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
  85. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
  86. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
  87. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
  88. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
  89. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
  90. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
  91. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
  92. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
  93. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
  94. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
  95. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
  96. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
  97. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
  98. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_select_star.py +0 -0
  99. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
  100. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
  101. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
  102. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
  103. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
  104. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
  105. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
  106. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
  107. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +0 -0
  108. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
  109. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
  110. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
  111. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
  112. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
  113. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
  114. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +0 -0
  115. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
  116. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
  117. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
  118. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
  119. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
  120. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
  121. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
  122. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
  123. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
  124. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
  125. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
  126. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
  127. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
  128. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
  129. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
  130. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
  131. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
  132. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
  133. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
  134. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +0 -0
  135. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
  136. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
  137. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
  138. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
  139. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
  140. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
  141. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
  142. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
  143. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
  144. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
  145. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
  146. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
  147. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
  148. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
  149. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
  150. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
  151. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
  152. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
  153. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
  154. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
  155. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
  156. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
  157. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
  158. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
  159. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/require_precise_factory_signature.py +0 -0
  160. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
  161. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
  162. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
  163. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
  164. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
  165. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
  166. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/stepdown.py +0 -0
  167. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
  168. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
  169. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
  170. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
  171. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
  172. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
  173. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
  174. {sarj_python_lint-1.16.2 → sarj_python_lint-1.16.3}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sarj-python-lint
3
- Version: 1.16.2
3
+ Version: 1.16.3
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.16.2"
3
+ version = "1.16.3"
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" }]
@@ -38,15 +38,17 @@ class UnusedTestFactoryOption(Rule):
38
38
  code = "SARJ443"
39
39
  documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
40
40
  default_level=Severity.WARNING,
41
- summary="A closed test-local factory exposes a literal option that its callers never vary.",
41
+ summary="A private test factory exposes an invariant literal or unexercised local callable option.",
42
42
  rationale="Unused customization obscures the values that actually distinguish test scenarios.",
43
- remediation="Consider keeping the invariant value in the test-local construction instead of exposing an unexercised option. Preserve shared factories and dependency-injection contracts.",
43
+ remediation="Consider keeping the invariant literal or stable local callable in the construction instead of exposing an unexercised option. Preserve intentional dependency contracts and callable default binding timing.",
44
44
  category=RuleCategory.TESTING,
45
45
  autofix=AutofixPolicy.NONE,
46
46
  limitations=(
47
- "Only private _make_ and _build_ helpers nested directly inside test functions are considered, with at least two known direct callers and straight-line construction bodies.",
48
- "Only literal options are considered. Callable dependency defaults, module-level/shared factories, decorated factories, escaping references, reflection, unpacking, rebinding and shadowing are excluded.",
47
+ "Literal findings consider only private _make_ and _build_ helpers nested directly inside test functions, with at least two known direct callers and straight-line construction bodies.",
48
+ "Callable findings consider module-level private helpers with the same construction shape and an earlier undecorated local function default, only when at least two known direct callers all omit that option.",
49
+ "Conftest callable factories, explicit callable arguments, exports, decorators, escaping references, reflection, unpacking, rebinding, shadowing and ambiguous mutation or patch targets are excluded.",
49
50
  "Same-name declarations elsewhere in the file conservatively exclude a helper. No autofix: this warning identifies unexercised customization, not an invalid callable contract.",
51
+ "Callable findings describe known callers in this file; cross-module and dynamic callers are not inferred. Retain intentional extension points with a reasoned exception, preserving definition-time default capture.",
50
52
  ),
51
53
  examples=(
52
54
  RuleExample(
@@ -63,6 +65,40 @@ class UnusedTestFactoryOption(Rule):
63
65
  expected_count=1,
64
66
  public=True,
65
67
  ),
68
+ RuleExample(
69
+ example_id="unused-local-callable-option",
70
+ scenario="callable-default",
71
+ title="Known callers do not replace a stable local dependency",
72
+ outcome=ExampleOutcome.MATCH,
73
+ files=(
74
+ ExampleFile.python(
75
+ "tests/test_widget.py",
76
+ "def _read():\n return 'ready'\n"
77
+ "def _make_widget(*, read=_read):\n return Widget(read=read)\n"
78
+ "_make_widget()\n_make_widget()\n",
79
+ ),
80
+ ),
81
+ focus_path=PurePosixPath("tests/test_widget.py"),
82
+ expected_count=1,
83
+ public=True,
84
+ ),
85
+ RuleExample(
86
+ example_id="exercised-local-callable-option",
87
+ scenario="callable-default",
88
+ title="An explicit callback preserves the dependency contract",
89
+ outcome=ExampleOutcome.NO_MATCH,
90
+ files=(
91
+ ExampleFile.python(
92
+ "tests/test_widget.py",
93
+ "def _read():\n return 'ready'\n"
94
+ "def _make_widget(*, read=_read):\n return Widget(read=read)\n"
95
+ "_make_widget()\n_make_widget(read=_read)\n",
96
+ ),
97
+ ),
98
+ focus_path=PurePosixPath("tests/test_widget.py"),
99
+ expected_count=0,
100
+ public=True,
101
+ ),
66
102
  RuleExample(
67
103
  example_id="exercised-size-option",
68
104
  title="Keep customization that a caller exercises",
@@ -96,14 +132,15 @@ class UnusedTestFactoryOption(Rule):
96
132
  lines = context.source_lines
97
133
  findings: list[Diagnostic] = []
98
134
  for function in context.nodes(ast.FunctionDef):
99
- owner = context.parents.get(function)
100
- if (
101
- not _is_factory(function)
102
- or not isinstance(owner, ast.FunctionDef | ast.AsyncFunctionDef)
103
- or not owner.name.startswith("test_")
104
- ):
135
+ if not _is_factory(function):
105
136
  continue
106
- findings.extend(_factory_findings(tree, function, path, lines, self.code, node_index=context.node_index))
137
+ owner = context.parents.get(function)
138
+ if isinstance(owner, ast.FunctionDef | ast.AsyncFunctionDef) and owner.name.startswith("test_"):
139
+ findings.extend(
140
+ _factory_findings(tree, function, path, lines, self.code, node_index=context.node_index)
141
+ )
142
+ elif owner is tree and path.name != "conftest.py":
143
+ findings.extend(_callable_factory_findings(context, function, self.code))
107
144
  return sorted(findings, key=lambda item: (item.line, item.col))
108
145
 
109
146
 
@@ -280,3 +317,79 @@ def _factory_options(function: ast.FunctionDef) -> list[tuple[ast.arg, ast.expr]
280
317
  ]
281
318
  used = {node.id for node in nodes(function, ast.Name) if isinstance(node.ctx, ast.Load)}
282
319
  return [(argument, default) for argument, default in defaults if argument.arg in used and default is not None]
320
+
321
+
322
+ def _callable_factory_findings(context: PythonFileContext, function: ast.FunctionDef, code: str) -> list[Diagnostic]:
323
+ tree = context.tree
324
+ if tree is None:
325
+ return []
326
+ options = [(argument, default) for argument, default in _factory_options(function) if isinstance(default, ast.Name)]
327
+ if not options:
328
+ return []
329
+ calls = _direct_calls(tree, function, node_index=context.node_index)
330
+ if len(calls) < _MIN_INVARIANT_CALLS:
331
+ return []
332
+ bound = _bound_calls(function, calls)
333
+ if bound is None:
334
+ return []
335
+ supplied = {name for arguments in bound for name in arguments}
336
+ rebound = {node.id for node in nodes(function, ast.Name) if not isinstance(node.ctx, ast.Load)}
337
+ findings: list[Diagnostic] = []
338
+ for argument, default in options:
339
+ if (
340
+ argument.arg in supplied | rebound
341
+ or not _is_stable_local_callable(context, function, default.id)
342
+ or is_suppressed(context.source_lines, argument.lineno, code)
343
+ ):
344
+ continue
345
+ findings.append(
346
+ Diagnostic(
347
+ path=context.path,
348
+ line=argument.lineno,
349
+ col=argument.col_offset + 1,
350
+ code=code,
351
+ severity=Severity.WARNING,
352
+ message=(
353
+ f"No known direct caller in this file supplies `{function.name}.{argument.arg}`; consider "
354
+ f"using the stable local callable `{default.id}` internally. Preserve default binding timing "
355
+ "and retain the option if external callers or an intentional test contract need it."
356
+ ),
357
+ )
358
+ )
359
+ return findings
360
+
361
+
362
+ def _is_stable_local_callable(context: PythonFileContext, factory: ast.FunctionDef, name: str) -> bool:
363
+ tree = context.tree
364
+ if tree is None or not any(
365
+ isinstance(node, ast.FunctionDef | ast.AsyncFunctionDef)
366
+ and node.name == name
367
+ and node.lineno < factory.lineno
368
+ and not node.decorator_list
369
+ for node in tree.body
370
+ ):
371
+ return False
372
+ if not _has_unambiguous_factory_name(tree, name, node_index=context.node_index):
373
+ return False
374
+ return not (
375
+ any(node.id == name and not isinstance(node.ctx, ast.Load) for node in context.nodes(ast.Name))
376
+ or any(
377
+ not isinstance(node.ctx, ast.Load) and any(child.id == name for child in nodes(node.value, ast.Name))
378
+ for node in context.nodes(ast.Attribute, ast.Subscript)
379
+ )
380
+ or any(
381
+ isinstance(node.value, str) and (name in node.value.split(".") or factory.name in node.value.split("."))
382
+ for node in context.nodes(ast.Constant)
383
+ )
384
+ or _provider_escapes(context, name)
385
+ )
386
+
387
+
388
+ def _provider_escapes(context: PythonFileContext, name: str) -> bool:
389
+ for node in context.nodes(ast.Name):
390
+ if node.id != name or not isinstance(node.ctx, ast.Load):
391
+ continue
392
+ parent = context.parents.get(node)
393
+ if not (isinstance(parent, ast.arguments) or (isinstance(parent, ast.Call) and parent.func is node)):
394
+ return True
395
+ return False