sarj-python-lint 1.25.4__tar.gz → 1.25.6__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 (183) hide show
  1. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/PKG-INFO +3 -3
  2. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/pyproject.toml +3 -3
  3. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_tautological_expect.py +118 -2
  4. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/.gitignore +0 -0
  5. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/LICENSE +0 -0
  6. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/README.md +0 -0
  7. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/__init__.py +0 -0
  8. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/__main__.py +0 -0
  9. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/_analysis_session.py +0 -0
  10. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/_file_context.py +0 -0
  11. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/_filesystem.py +0 -0
  12. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/_python_target.py +0 -0
  13. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/_ratchet_cli.py +0 -0
  14. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/_secret_names.py +0 -0
  15. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/_source.py +0 -0
  16. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/_version.py +0 -0
  17. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/benchmark.py +0 -0
  18. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/json_boundary.py +0 -0
  19. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/py.typed +0 -0
  20. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/ratchet.py +0 -0
  21. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rule_base.py +0 -0
  22. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/__init__.py +0 -0
  23. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
  24. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_ast_index.py +0 -0
  25. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_ast_position.py +0 -0
  26. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_comments.py +0 -0
  27. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
  28. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_copy_on_write.py +0 -0
  29. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
  30. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_docstrings.py +0 -0
  31. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_fastapi.py +0 -0
  32. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_first_party.py +0 -0
  33. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
  34. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_imports.py +0 -0
  35. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_local_source.py +0 -0
  36. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_logging.py +0 -0
  37. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
  38. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_paths.py +0 -0
  39. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_project_index.py +0 -0
  40. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
  41. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_pytest.py +0 -0
  42. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_registry.py +0 -0
  43. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
  44. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_set_fields.py +0 -0
  45. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_sql.py +0 -0
  46. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
  47. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
  48. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_test_composition.py +0 -0
  49. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/_test_provenance.py +0 -0
  50. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
  51. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
  52. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
  53. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
  54. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
  55. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
  56. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
  57. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
  58. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
  59. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
  60. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
  61. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
  62. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
  63. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
  64. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
  65. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
  66. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
  67. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_before_validator_input_mutation.py +0 -0
  68. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_broad_keyword_capture.py +0 -0
  69. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
  70. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
  71. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
  72. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
  73. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
  74. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
  75. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
  76. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
  77. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
  78. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
  79. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
  80. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
  81. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
  82. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
  83. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
  84. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
  85. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
  86. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_input_model_mutation.py +0 -0
  87. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
  88. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_mocked_pydantic_value_object.py +0 -0
  89. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
  90. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
  91. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
  92. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
  93. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
  94. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
  95. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
  96. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
  97. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
  98. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
  99. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
  100. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
  101. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
  102. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
  103. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_select_star.py +0 -0
  104. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
  105. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
  106. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
  107. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
  108. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_test_method_grafting.py +0 -0
  109. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
  110. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
  111. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
  112. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_unused_copy_result.py +0 -0
  113. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +0 -0
  114. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
  115. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
  116. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
  117. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
  118. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
  119. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
  120. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +0 -0
  121. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
  122. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
  123. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
  124. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
  125. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
  126. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
  127. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
  128. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
  129. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
  130. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
  131. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
  132. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
  133. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
  134. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
  135. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
  136. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_native_string_check.py +0 -0
  137. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
  138. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
  139. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
  140. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
  141. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +0 -0
  142. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
  143. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_required_constructor_parameters.py +0 -0
  144. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
  145. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
  146. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
  147. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
  148. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
  149. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
  150. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
  151. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
  152. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
  153. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
  154. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
  155. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
  156. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
  157. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
  158. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
  159. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
  160. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
  161. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
  162. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
  163. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
  164. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
  165. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
  166. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
  167. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/require_precise_factory_signature.py +0 -0
  168. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
  169. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
  170. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
  171. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
  172. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
  173. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
  174. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/stepdown.py +0 -0
  175. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
  176. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
  177. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
  178. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
  179. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
  180. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
  181. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
  182. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
  183. {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.6}/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.25.4
3
+ Version: 1.25.6
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/
@@ -18,8 +18,8 @@ Classifier: Programming Language :: Python :: 3.14
18
18
  Classifier: Topic :: Software Development :: Quality Assurance
19
19
  Requires-Python: >=3.14
20
20
  Requires-Dist: packaging==26.3
21
- Requires-Dist: ruff>=0.16.9
22
- Requires-Dist: sarj-rule-contracts==0.2.0
21
+ Requires-Dist: ruff>=0.16.10
22
+ Requires-Dist: sarj-rule-contracts==0.2.1
23
23
  Requires-Dist: sqlglot==30.19.0
24
24
  Requires-Dist: typer==0.27.2
25
25
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sarj-python-lint"
3
- version = "1.25.4"
3
+ version = "1.25.6"
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.2.0", "packaging==26.3", "ruff>=0.16.9", "sqlglot==30.19.0", "typer==0.27.2"]
18
+ dependencies = ["sarj-rule-contracts==0.2.1", "packaging==26.3", "ruff>=0.16.10", "sqlglot==30.19.0", "typer==0.27.2"]
19
19
 
20
20
  [project.scripts]
21
21
  sarj-python-lint = "sarj_python_lint.__main__:main"
@@ -31,7 +31,7 @@ Issues = "https://github.com/sarj-ai/code-standards/issues"
31
31
  [dependency-groups]
32
32
  dev = [
33
33
  "pytest>=9.1.1",
34
- "ruff>=0.16.9",
34
+ "ruff>=0.16.10",
35
35
  "basedpyright>=1.40.1",
36
36
  ]
37
37
 
@@ -15,6 +15,7 @@ from sarj_python_lint.rule_base import (
15
15
  Severity,
16
16
  )
17
17
  from sarj_python_lint.rules._ast_index import walk as walk_ast
18
+ from sarj_python_lint.rules._paths import is_test_path
18
19
 
19
20
 
20
21
  if TYPE_CHECKING:
@@ -32,13 +33,14 @@ _FAIL = "fail"
32
33
 
33
34
  # Enough of the operand to identify it in the message without pasting a screenful.
34
35
  _OPERAND_PREVIEW_CHARS = 40
36
+ _UNKNOWN = object()
35
37
 
36
38
 
37
39
  class NoTautologicalExpect(Rule):
38
40
  id: str = "no-statically-truthy-assertion"
39
41
  code: str = "SARJ057"
40
42
  documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
41
- summary="A bare assertion condition is statically truthy.",
43
+ summary="An assertion condition is statically truthy, including test-local scalar setup.",
42
44
  rationale=(
43
45
  "A condition that stays truthy whenever evaluation succeeds cannot reject an incorrect result and often "
44
46
  "means the intended condition was wrapped in a container or placed in the message slot."
@@ -51,10 +53,40 @@ class NoTautologicalExpect(Rule):
51
53
  aliases=("no-tautological-expect",),
52
54
  limitations=(
53
55
  "Detection covers truthy scalar constants and definitely non-empty list, set, and dict displays.",
56
+ "Test-local immutable scalar bindings and their aliases are tracked only through straight-line assignments; calls, control flow, mutable values, and global/nonlocal writes invalidate tracking.",
54
57
  "Ruff owns asserted strings and tuples, literal comparisons and identity, and unittest-style assertion methods.",
55
58
  "Generated files, always-failing assertions, deliberate match-arm success markers, and runtime-value comparisons are excluded.",
56
59
  ),
57
60
  examples=(
61
+ RuleExample(
62
+ example_id="setup-only-oracle",
63
+ scenario="setup-only",
64
+ title="A test asserts only on its own fixed setup",
65
+ outcome=ExampleOutcome.MATCH,
66
+ files=(
67
+ ExampleFile.python(
68
+ "tests/test_service.py", "def test_service():\n status = 'ok'\n assert status == 'ok'\n"
69
+ ),
70
+ ),
71
+ focus_path=PurePosixPath("tests/test_service.py"),
72
+ expected_count=1,
73
+ public=True,
74
+ ),
75
+ RuleExample(
76
+ example_id="produced-scalar-oracle",
77
+ scenario="setup-only",
78
+ title="Assert on a value returned by the application",
79
+ outcome=ExampleOutcome.NO_MATCH,
80
+ files=(
81
+ ExampleFile.python(
82
+ "tests/test_service.py",
83
+ "def test_service():\n status = service_status()\n assert status == 'ok'\n",
84
+ ),
85
+ ),
86
+ focus_path=PurePosixPath("tests/test_service.py"),
87
+ expected_count=0,
88
+ public=True,
89
+ ),
58
90
  RuleExample(
59
91
  example_id="condition-in-message-slot",
60
92
  title="The intended condition became an assertion message",
@@ -96,6 +128,9 @@ class NoTautologicalExpect(Rule):
96
128
  if tree is None:
97
129
  return []
98
130
  exempt = _exempt_nodes(tree, node_index=context.node_index)
131
+ tautologies = _tautologies(tree, exempt, node_index=context.node_index)
132
+ if is_test_path(path) and path.name != "conftest.py":
133
+ tautologies.extend(_bound_tautologies(context))
99
134
  diags = [
100
135
  Diagnostic(
101
136
  path=path,
@@ -105,12 +140,93 @@ class NoTautologicalExpect(Rule):
105
140
  message=_message(node, reason),
106
141
  severity=Severity.ERROR,
107
142
  )
108
- for node, reason in _tautologies(tree, exempt, node_index=context.node_index)
143
+ for node, reason in tautologies
109
144
  ]
110
145
  diags.sort(key=lambda d: (d.line, d.col))
111
146
  return diags
112
147
 
113
148
 
149
+ def _bound_tautologies(context: PythonFileContext) -> list[_Tautology]:
150
+ found: list[_Tautology] = []
151
+ external_writes = context.nodes(ast.Global, ast.Nonlocal)
152
+ for function in context.nodes(ast.FunctionDef, ast.AsyncFunctionDef):
153
+ if not function.name.startswith("test_"):
154
+ continue
155
+ if any(function.lineno <= node.lineno <= (function.end_lineno or function.lineno) for node in external_writes):
156
+ continue
157
+ found.extend(_function_bound_tautologies(function))
158
+ return found
159
+
160
+
161
+ def _function_bound_tautologies(function: ast.FunctionDef | ast.AsyncFunctionDef) -> list[_Tautology]:
162
+ found: list[_Tautology] = []
163
+ bindings: dict[str, object] = {}
164
+ for statement in function.body:
165
+ if _record_scalar_assignment(statement, bindings):
166
+ continue
167
+ if isinstance(statement, ast.Assert):
168
+ references_setup = any(
169
+ isinstance(node, ast.Name) and node.id in bindings for node in ast.walk(statement.test)
170
+ )
171
+ if references_setup and _scalar_condition(statement.test, bindings) is True:
172
+ found.append(_Tautology(statement, "the condition follows only from unchanged scalar setup"))
173
+ bindings.clear()
174
+ return found
175
+
176
+
177
+ def _record_scalar_assignment(statement: ast.stmt, bindings: dict[str, object]) -> bool:
178
+ match statement:
179
+ case (
180
+ ast.Assign(targets=[ast.Name(id=name)], value=value) | ast.AnnAssign(target=ast.Name(id=name), value=value)
181
+ ) if value is not None:
182
+ scalar = _scalar_value(value, bindings)
183
+ if scalar is not _UNKNOWN:
184
+ bindings[name] = scalar
185
+ return True
186
+ case _:
187
+ pass
188
+ return False
189
+
190
+
191
+ def _scalar_value(node: ast.expr, bindings: dict[str, object]) -> object:
192
+ if isinstance(node, ast.Name):
193
+ return bindings.get(node.id, _UNKNOWN)
194
+ if isinstance(node, ast.Constant):
195
+ value: object = node.value
196
+ return value if value is None or isinstance(value, (bool, int, float, str, bytes)) else _UNKNOWN
197
+ if isinstance(node, ast.UnaryOp):
198
+ value = _scalar_value(node.operand, bindings)
199
+ if isinstance(node.op, ast.Not) and value is not _UNKNOWN:
200
+ return not value
201
+ if isinstance(value, (int, float)):
202
+ if isinstance(node.op, ast.USub):
203
+ return -value
204
+ if isinstance(node.op, ast.UAdd):
205
+ return +value
206
+ return _UNKNOWN
207
+
208
+
209
+ def _scalar_condition(node: ast.expr, bindings: dict[str, object]) -> bool | None:
210
+ if isinstance(node, ast.Compare) and len(node.ops) == 1:
211
+ left = _scalar_value(node.left, bindings)
212
+ right = _scalar_value(node.comparators[0], bindings)
213
+ if left is _UNKNOWN or right is _UNKNOWN:
214
+ return None
215
+ match node.ops[0]:
216
+ case ast.Eq():
217
+ return left == right
218
+ case ast.NotEq():
219
+ return left != right
220
+ case ast.Is() if left is None or isinstance(left, bool):
221
+ return left is right
222
+ case ast.IsNot() if left is None or isinstance(left, bool):
223
+ return left is not right
224
+ case _:
225
+ return None
226
+ value = _scalar_value(node, bindings)
227
+ return None if value is _UNKNOWN else bool(value)
228
+
229
+
114
230
  def _exempt_nodes(tree: ast.Module, *, node_index: NodeIndex | None = None) -> set[ast.AST]:
115
231
  exempt: set[ast.AST] = set()
116
232
  for node in walk_ast(tree, index=node_index):