sarj-python-lint 1.25.3__tar.gz → 1.25.4__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.3 → sarj_python_lint-1.25.4}/PKG-INFO +1 -1
  2. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/pyproject.toml +1 -1
  3. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/__main__.py +30 -21
  4. sarj_python_lint-1.25.4/src/sarj_python_lint/_source.py +14 -0
  5. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/ratchet.py +2 -1
  6. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_fastapi.py +2 -1
  7. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_local_source.py +2 -1
  8. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_nominal_project.py +2 -1
  9. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_project_index.py +2 -1
  10. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +2 -1
  11. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +3 -2
  12. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/.gitignore +0 -0
  13. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/LICENSE +0 -0
  14. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/README.md +0 -0
  15. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/__init__.py +0 -0
  16. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/_analysis_session.py +0 -0
  17. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/_file_context.py +0 -0
  18. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/_filesystem.py +0 -0
  19. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/_python_target.py +0 -0
  20. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/_ratchet_cli.py +0 -0
  21. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/_secret_names.py +0 -0
  22. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/_version.py +0 -0
  23. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/benchmark.py +0 -0
  24. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/json_boundary.py +0 -0
  25. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/py.typed +0 -0
  26. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rule_base.py +0 -0
  27. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/__init__.py +0 -0
  28. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
  29. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_ast_index.py +0 -0
  30. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_ast_position.py +0 -0
  31. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_comments.py +0 -0
  32. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
  33. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_copy_on_write.py +0 -0
  34. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
  35. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_docstrings.py +0 -0
  36. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_first_party.py +0 -0
  37. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
  38. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_imports.py +0 -0
  39. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_logging.py +0 -0
  40. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_paths.py +0 -0
  41. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
  42. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_pytest.py +0 -0
  43. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_registry.py +0 -0
  44. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
  45. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_set_fields.py +0 -0
  46. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_sql.py +0 -0
  47. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
  48. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
  49. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_test_composition.py +0 -0
  50. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/_test_provenance.py +0 -0
  51. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
  52. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
  53. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
  54. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
  55. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
  56. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
  57. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
  58. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
  59. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
  60. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
  61. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
  62. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
  63. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
  64. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
  65. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
  66. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
  67. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_before_validator_input_mutation.py +0 -0
  68. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_broad_keyword_capture.py +0 -0
  69. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
  70. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
  71. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
  72. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
  73. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
  74. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
  75. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
  76. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
  77. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
  78. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
  79. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
  80. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
  81. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
  82. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
  83. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
  84. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
  85. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_input_model_mutation.py +0 -0
  86. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
  87. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_mocked_pydantic_value_object.py +0 -0
  88. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
  89. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
  90. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
  91. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
  92. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
  93. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
  94. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
  95. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
  96. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
  97. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
  98. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
  99. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
  100. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
  101. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
  102. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_select_star.py +0 -0
  103. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
  104. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
  105. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
  106. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
  107. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
  108. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_test_method_grafting.py +0 -0
  109. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
  110. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
  111. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
  112. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_unused_copy_result.py +0 -0
  113. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +0 -0
  114. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
  115. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
  116. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
  117. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
  118. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
  119. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
  120. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +0 -0
  121. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
  122. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
  123. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
  124. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
  125. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
  126. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
  127. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
  128. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
  129. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
  130. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
  131. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
  132. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
  133. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
  134. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
  135. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
  136. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_native_string_check.py +0 -0
  137. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
  138. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
  139. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
  140. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
  141. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +0 -0
  142. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
  143. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_required_constructor_parameters.py +0 -0
  144. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
  145. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
  146. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
  147. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
  148. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
  149. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
  150. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
  151. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
  152. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
  153. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
  154. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
  155. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
  156. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
  157. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
  158. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
  159. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
  160. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
  161. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
  162. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
  163. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
  164. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
  165. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
  166. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
  167. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/require_precise_factory_signature.py +0 -0
  168. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
  169. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
  170. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
  171. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
  172. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
  173. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
  174. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/stepdown.py +0 -0
  175. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
  176. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
  177. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
  178. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
  179. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
  180. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
  181. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
  182. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
  183. {sarj_python_lint-1.25.3 → sarj_python_lint-1.25.4}/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.3
3
+ Version: 1.25.4
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.25.3"
3
+ version = "1.25.4"
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" }]
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import ast
4
4
  from collections import Counter
5
+ from contextlib import suppress
5
6
  from dataclasses import dataclass
6
7
  from fnmatch import fnmatch
7
8
  import json
@@ -16,6 +17,7 @@ from sarj_python_lint import __version__
16
17
  from sarj_python_lint._analysis_session import AnalysisSession
17
18
  from sarj_python_lint._file_context import PythonFileContext
18
19
  from sarj_python_lint._filesystem import atomic_write_text
20
+ from sarj_python_lint._source import read_python_source
19
21
  from sarj_python_lint.json_boundary import is_object_mapping, parse_json
20
22
  from sarj_python_lint.rule_base import Diagnostic, ProjectRule, Rule, Severity, is_suppressed
21
23
  from sarj_python_lint.rules import REGISTRY
@@ -110,7 +112,7 @@ def _check(rule_ids: list[str], paths: list[Path]) -> list[Diagnostic]:
110
112
  loaded: dict[Path, str] = {}
111
113
  for path in expanded:
112
114
  try:
113
- loaded[path] = path.read_text(encoding="utf-8", errors="replace")
115
+ loaded[path] = read_python_source(path)
114
116
  except OSError:
115
117
  continue
116
118
  project_rules = [rule for rule in rules if isinstance(rule, ProjectRule)]
@@ -138,6 +140,7 @@ def check_source(
138
140
  if diagnostic.code == "SARJ419" or not is_suppressed(source_lines, diagnostic.line, diagnostic.code)
139
141
  ],
140
142
  source=source,
143
+ context=context,
141
144
  )
142
145
 
143
146
 
@@ -187,21 +190,27 @@ class _OwnerLocation(NamedTuple):
187
190
  column: int
188
191
 
189
192
 
190
- def deduplicate_diagnostics(diags: list[Diagnostic], *, source: str | None = None) -> list[Diagnostic]:
191
- diags = _deduplicate_test_composition(diags, source)
193
+ def deduplicate_diagnostics(
194
+ diags: list[Diagnostic], *, source: str | None = None, context: PythonFileContext | None = None
195
+ ) -> list[Diagnostic]:
192
196
  codes = frozenset(diagnostic.code for diagnostic in diags)
193
197
  needs_docstring_owners = ("SARJ092" in codes and not codes.isdisjoint(_DIAGNOSTIC_PRECEDENCE["SARJ092"])) or (
194
198
  "SARJ420" in codes and not codes.isdisjoint(_DOCSTRING_PRECEDENCE_CODES)
195
199
  )
196
- docstring_owners = _docstring_owner_locations(source) if source is not None and needs_docstring_owners else {}
197
200
  needs_signature_owners = (
198
201
  ("SARJ093" in codes and "SARJ034" in codes)
199
202
  or ("SARJ447" in codes and "SARJ008" in codes)
200
203
  or ("SARJ094" in codes and not codes.isdisjoint(_DIAGNOSTIC_PRECEDENCE["SARJ094"]))
201
204
  )
202
- signature_owners = (
203
- _function_signature_owner_locations(source) if source is not None and needs_signature_owners else {}
205
+ needs_composition_owners = {"SARJ066", "SARJ457"} <= codes
206
+ tree = (
207
+ _diagnostic_owner_tree(source, context)
208
+ if needs_docstring_owners or needs_signature_owners or needs_composition_owners
209
+ else None
204
210
  )
211
+ diags = _deduplicate_test_composition(diags, tree)
212
+ docstring_owners = _docstring_owner_locations(tree) if needs_docstring_owners else {}
213
+ signature_owners = _function_signature_owner_locations(tree) if needs_signature_owners else {}
205
214
 
206
215
  def owner_location(diagnostic: Diagnostic) -> _OwnerLocation:
207
216
  if diagnostic.code in {"SARJ008", "SARJ034", "SARJ093", "SARJ094", "SARJ447"}:
@@ -236,13 +245,19 @@ def deduplicate_diagnostics(diags: list[Diagnostic], *, source: str | None = Non
236
245
  ]
237
246
 
238
247
 
239
- def _deduplicate_test_composition(diags: list[Diagnostic], source: str | None) -> list[Diagnostic]:
248
+ def _diagnostic_owner_tree(source: str | None, context: PythonFileContext | None) -> ast.Module | None:
249
+ if source is None:
250
+ return None
251
+ if context is not None and context.source == source:
252
+ return context.tree
253
+ with suppress(SyntaxError):
254
+ return ast.parse(source)
255
+ return None
256
+
257
+
258
+ def _deduplicate_test_composition(diags: list[Diagnostic], tree: ast.Module | None) -> list[Diagnostic]:
240
259
  codes = {diagnostic.code for diagnostic in diags}
241
- if source is None or not {"SARJ066", "SARJ457"} <= codes:
242
- return diags
243
- try:
244
- tree = ast.parse(source)
245
- except SyntaxError:
260
+ if tree is None or not {"SARJ066", "SARJ457"} <= codes:
246
261
  return diags
247
262
  whole_tests = {
248
263
  (diagnostic.path, diagnostic.line): diagnostic.severity for diagnostic in diags if diagnostic.code == "SARJ066"
@@ -312,10 +327,8 @@ def _typed_docstring_warning_is_superseded(codes: dict[str, set[Severity]]) -> b
312
327
  return any(Severity.ERROR in codes.get(generic, set()) for generic in ("SARJ086", "SARJ087"))
313
328
 
314
329
 
315
- def _function_signature_owner_locations(source: str) -> dict[int, _OwnerLocation]:
316
- try:
317
- tree = ast.parse(source)
318
- except SyntaxError:
330
+ def _function_signature_owner_locations(tree: ast.Module | None) -> dict[int, _OwnerLocation]:
331
+ if tree is None:
319
332
  return {}
320
333
  owners: dict[int, _OwnerLocation] = {}
321
334
  for node in ast.walk(tree):
@@ -327,11 +340,7 @@ def _function_signature_owner_locations(source: str) -> dict[int, _OwnerLocation
327
340
  return owners
328
341
 
329
342
 
330
- def _docstring_owner_locations(source: str) -> dict[int, _OwnerLocation]:
331
- try:
332
- tree = ast.parse(source)
333
- except SyntaxError:
334
- tree = None
343
+ def _docstring_owner_locations(tree: ast.Module | None) -> dict[int, _OwnerLocation]:
335
344
  if tree is None:
336
345
  return {}
337
346
  owners: dict[int, _OwnerLocation] = {}
@@ -0,0 +1,14 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Final
4
+
5
+
6
+ if TYPE_CHECKING:
7
+ from pathlib import Path
8
+
9
+
10
+ PYTHON_SOURCE_ENCODING: Final = "utf-8-sig"
11
+
12
+
13
+ def read_python_source(path: Path) -> str:
14
+ return path.read_text(encoding=PYTHON_SOURCE_ENCODING, errors="replace")
@@ -9,6 +9,7 @@ import tokenize
9
9
  from types import MappingProxyType
10
10
  from typing import TYPE_CHECKING, Final, NamedTuple, TypeGuard
11
11
 
12
+ from sarj_python_lint._source import PYTHON_SOURCE_ENCODING
12
13
  from sarj_python_lint.json_boundary import is_object_mapping, parse_json
13
14
 
14
15
 
@@ -329,7 +330,7 @@ def _python_files(root: Path, excluded_dir_names: frozenset[str]) -> Iterator[Pa
329
330
 
330
331
  def _read(path: Path) -> str:
331
332
  try:
332
- return path.read_text(encoding="utf-8")
333
+ return path.read_text(encoding=PYTHON_SOURCE_ENCODING)
333
334
  except UnicodeDecodeError, OSError:
334
335
  return ""
335
336
 
@@ -5,6 +5,7 @@ from collections import Counter
5
5
  from dataclasses import dataclass
6
6
  from typing import TYPE_CHECKING, Literal, NamedTuple
7
7
 
8
+ from sarj_python_lint._source import read_python_source
8
9
  from sarj_python_lint.rules._ast_index import walk as walk_ast
9
10
  from sarj_python_lint.rules._imports import ImportIndex
10
11
 
@@ -839,7 +840,7 @@ def _read_module(path: Path, cache: dict[Path, ast.Module | None]) -> ast.Module
839
840
  if path.stat().st_size > _MAX_IMPORTED_MODULE_BYTES:
840
841
  tree = None
841
842
  else:
842
- tree = ast.parse(path.read_text(encoding="utf-8", errors="replace"), filename=str(path))
843
+ tree = ast.parse(read_python_source(path), filename=str(path))
843
844
  except OSError, SyntaxError:
844
845
  tree = None
845
846
  cache[path] = tree
@@ -5,6 +5,7 @@ from dataclasses import dataclass
5
5
  from pathlib import Path
6
6
  from typing import TYPE_CHECKING, final
7
7
 
8
+ from sarj_python_lint._source import PYTHON_SOURCE_ENCODING
8
9
  from sarj_python_lint.rules._imports import ImportIndex
9
10
 
10
11
 
@@ -113,7 +114,7 @@ def _read_module(path: Path) -> LocalModule | None:
113
114
  data = stream.read(_MAX_MODULE_BYTES + 1)
114
115
  if len(data) > _MAX_MODULE_BYTES:
115
116
  return None
116
- source = data.decode("utf-8")
117
+ source = data.decode(PYTHON_SOURCE_ENCODING)
117
118
  tree = ast.parse(source, filename=str(path))
118
119
  except OSError, UnicodeError, SyntaxError:
119
120
  return None
@@ -11,6 +11,7 @@ from typing import TYPE_CHECKING, TypeGuard, final
11
11
  from packaging.requirements import InvalidRequirement, Requirement
12
12
  from packaging.utils import canonicalize_name
13
13
 
14
+ from sarj_python_lint._source import PYTHON_SOURCE_ENCODING
14
15
  from sarj_python_lint.rules._first_party import distribution_root
15
16
  from sarj_python_lint.rules._imports import ImportIndex
16
17
  from sarj_python_lint.rules._paths import is_generated
@@ -264,7 +265,7 @@ def _source(path: Path) -> NominalSource | None:
264
265
  try:
265
266
  if path.is_symlink() or path.stat().st_size > _MAX_BYTES:
266
267
  return None
267
- text = path.read_text(encoding="utf-8")
268
+ text = path.read_text(encoding=PYTHON_SOURCE_ENCODING)
268
269
  if is_generated(path, text):
269
270
  return None
270
271
  except OSError, UnicodeError:
@@ -11,6 +11,7 @@ import re
11
11
  from types import MappingProxyType
12
12
  from typing import TYPE_CHECKING, final
13
13
 
14
+ from sarj_python_lint._source import read_python_source
14
15
  from sarj_python_lint.rules._ast_index import walk as walk_ast
15
16
  from sarj_python_lint.rules._first_party import FirstPartyFacts, project_root
16
17
  from sarj_python_lint.rules._paths import is_generated
@@ -532,7 +533,7 @@ def _read_bounded_source(root: Path, path: Path) -> LoadedSource | None:
532
533
  return None
533
534
  resolved = path.resolve()
534
535
  resolved.relative_to(root.resolve())
535
- return LoadedSource(resolved, resolved.read_text(encoding="utf-8", errors="replace"))
536
+ return LoadedSource(resolved, read_python_source(resolved))
536
537
  except OSError, ValueError:
537
538
  return None
538
539
 
@@ -5,6 +5,7 @@ from dataclasses import dataclass
5
5
  from pathlib import Path, PurePosixPath
6
6
  from typing import TYPE_CHECKING, NamedTuple, final, override
7
7
 
8
+ from sarj_python_lint._source import read_python_source
8
9
  from sarj_python_lint.rule_base import (
9
10
  AutofixPolicy,
10
11
  Diagnostic,
@@ -688,7 +689,7 @@ def _read_module(path: Path) -> ast.Module | None:
688
689
  try:
689
690
  if path.stat().st_size > _MAX_IMPORTED_MODULE_BYTES:
690
691
  return None
691
- tree = ast.parse(path.read_text(encoding="utf-8", errors="replace"), filename=str(path))
692
+ tree = ast.parse(read_python_source(path), filename=str(path))
692
693
  except OSError, SyntaxError:
693
694
  return None
694
695
  return tree
@@ -7,6 +7,7 @@ import os
7
7
  from pathlib import Path, PurePosixPath
8
8
  from typing import TYPE_CHECKING, ClassVar, NamedTuple, final, override
9
9
 
10
+ from sarj_python_lint._source import read_python_source
10
11
  from sarj_python_lint.rule_base import (
11
12
  Diagnostic,
12
13
  ExampleFile,
@@ -718,7 +719,7 @@ def _read_module(path: Path, facts: RuntimeConfigFacts) -> ast.Module:
718
719
  if cached is not None:
719
720
  return cached
720
721
  try:
721
- tree = ast.parse(path.read_text(encoding="utf-8", errors="replace"), filename=str(path))
722
+ tree = ast.parse(read_python_source(path), filename=str(path))
722
723
  except OSError, SyntaxError:
723
724
  tree = ast.Module(body=[], type_ignores=[])
724
725
  facts.modules[path] = tree
@@ -781,7 +782,7 @@ def _candidate_calls_class(
781
782
  if is_test_path(candidate):
782
783
  return False
783
784
  try:
784
- source = candidate.read_text(encoding="utf-8", errors="replace")
785
+ source = read_python_source(candidate)
785
786
  except OSError:
786
787
  return False
787
788
  if class_name not in source or is_generated(candidate, source):