sarj-python-lint 1.28.3__tar.gz → 1.28.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 (192) hide show
  1. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/PKG-INFO +1 -1
  2. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/pyproject.toml +1 -1
  3. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/_file_context.py +6 -0
  4. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_docstrings.py +90 -0
  5. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/redundant_class_docstring.py +1 -89
  6. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/redundant_docstring.py +3 -90
  7. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/.gitignore +0 -0
  8. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/LICENSE +0 -0
  9. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/README.md +0 -0
  10. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/__init__.py +0 -0
  11. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/__main__.py +0 -0
  12. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/_analysis_session.py +0 -0
  13. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/_filesystem.py +0 -0
  14. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/_python_target.py +0 -0
  15. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/_ratchet_cli.py +0 -0
  16. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/_secret_names.py +0 -0
  17. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/_source.py +0 -0
  18. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/_version.py +0 -0
  19. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/benchmark.py +0 -0
  20. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/interpreter_argv.py +0 -0
  21. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/json_boundary.py +0 -0
  22. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/py.typed +0 -0
  23. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/ratchet.py +0 -0
  24. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rule_base.py +0 -0
  25. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/__init__.py +0 -0
  26. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
  27. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_ast_index.py +0 -0
  28. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_ast_position.py +0 -0
  29. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_closed_helpers.py +0 -0
  30. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_comments.py +0 -0
  31. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
  32. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_copy_on_write.py +0 -0
  33. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
  34. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_fastapi.py +0 -0
  35. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_first_party.py +0 -0
  36. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
  37. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_imports.py +0 -0
  38. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_local_source.py +0 -0
  39. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_logging.py +0 -0
  40. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
  41. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_paths.py +0 -0
  42. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_project_index.py +0 -0
  43. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
  44. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_pytest.py +0 -0
  45. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_registry.py +0 -0
  46. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
  47. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_set_fields.py +0 -0
  48. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_sql.py +0 -0
  49. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
  50. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
  51. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_test_composition.py +0 -0
  52. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/_test_provenance.py +0 -0
  53. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
  54. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
  55. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
  56. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
  57. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
  58. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
  59. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/duplicate_adjacent_exception_handler.py +0 -0
  60. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/duplicate_closed_pure_helper.py +0 -0
  61. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
  62. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
  63. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
  64. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
  65. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
  66. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
  67. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
  68. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
  69. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
  70. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
  71. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
  72. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_before_validator_input_mutation.py +0 -0
  73. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_broad_keyword_capture.py +0 -0
  74. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
  75. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
  76. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
  77. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
  78. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
  79. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
  80. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
  81. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
  82. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
  83. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
  84. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
  85. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
  86. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
  87. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_fixed_sleep_in_loop.py +0 -0
  88. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
  89. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
  90. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
  91. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
  92. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_input_model_mutation.py +0 -0
  93. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_interpreter_source_arguments.py +0 -0
  94. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
  95. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_mocked_pydantic_value_object.py +0 -0
  96. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
  97. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
  98. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
  99. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
  100. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
  101. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
  102. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
  103. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
  104. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
  105. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
  106. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
  107. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
  108. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
  109. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
  110. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_select_star.py +0 -0
  111. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
  112. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
  113. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
  114. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
  115. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
  116. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_test_method_grafting.py +0 -0
  117. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
  118. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
  119. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
  120. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_unused_copy_result.py +0 -0
  121. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +0 -0
  122. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
  123. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
  124. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
  125. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
  126. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
  127. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
  128. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +0 -0
  129. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
  130. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
  131. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
  132. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
  133. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
  134. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
  135. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
  136. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
  137. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
  138. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
  139. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
  140. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
  141. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
  142. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
  143. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
  144. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_native_string_check.py +0 -0
  145. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
  146. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
  147. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
  148. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
  149. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +0 -0
  150. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
  151. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_required_constructor_parameters.py +0 -0
  152. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
  153. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
  154. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
  155. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
  156. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
  157. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
  158. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
  159. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
  160. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
  161. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
  162. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
  163. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
  164. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/redundant_test_constructor_forwarder.py +0 -0
  165. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
  166. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
  167. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
  168. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/repeated_unimplemented_test_contract.py +0 -0
  169. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
  170. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
  171. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
  172. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/require_injectable_retry_sleep.py +0 -0
  173. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
  174. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
  175. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
  176. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/require_precise_factory_signature.py +0 -0
  177. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
  178. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
  179. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
  180. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
  181. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
  182. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
  183. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/stepdown.py +0 -0
  184. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
  185. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
  186. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
  187. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
  188. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
  189. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
  190. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
  191. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.4}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
  192. {sarj_python_lint-1.28.3 → sarj_python_lint-1.28.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.28.3
3
+ Version: 1.28.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.28.3"
3
+ version = "1.28.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" }]
@@ -61,6 +61,12 @@ class PythonFileContext:
61
61
  def has_wildcard_import(self) -> bool:
62
62
  return any(alias.name == "*" for node in self.nodes(ast.ImportFrom) for alias in node.names)
63
63
 
64
+ @cached_property
65
+ def consumed_docstring_names(self) -> frozenset[str]:
66
+ from sarj_python_lint.rules._docstrings import consumed_docstring_names # ruff: ignore[import-outside-top-level] -- share runtime docstring analysis only when requested.
67
+
68
+ return consumed_docstring_names(self._valid_tree(), node_index=self.node_index)
69
+
64
70
  @property
65
71
  def parents(self) -> Mapping[ast.AST, ast.AST]:
66
72
  return self.node_index.parents
@@ -5,12 +5,17 @@ from itertools import starmap
5
5
  import re
6
6
  from typing import TYPE_CHECKING, NamedTuple
7
7
 
8
+ from sarj_python_lint.rules._ast_index import walk as walk_ast
8
9
  from sarj_python_lint.rules._comments import split_identifier, stem
9
10
 
10
11
 
11
12
  if TYPE_CHECKING:
12
13
  from collections.abc import Iterable
13
14
 
15
+ from sarj_python_lint.rules._ast_index import NodeIndex
16
+
17
+
18
+ _GETATTR_MIN_ARGS = 2
14
19
 
15
20
  # Docstring filler that says nothing about *which* thing is being described.
16
21
  _BASE_STOPWORDS = frozenset(
@@ -325,3 +330,88 @@ def restates(text: str, known: Iterable[str]) -> bool:
325
330
  if not content:
326
331
  return False
327
332
  return all(stem(word) in known_stems for word in content)
333
+
334
+
335
+ def consumed_docstring_names(tree: ast.Module, *, node_index: NodeIndex | None = None) -> frozenset[str]:
336
+ consumed: set[str] = set()
337
+ aliases: dict[str, set[str]] = {}
338
+ for node in walk_ast(tree, index=node_index):
339
+ _record_docstring_use(node, consumed, aliases)
340
+ changed = True
341
+ while changed:
342
+ changed = False
343
+ for alias, originals in aliases.items():
344
+ if alias not in consumed:
345
+ continue
346
+ before = len(consumed)
347
+ consumed.update(originals)
348
+ changed |= len(consumed) != before
349
+ return frozenset(consumed)
350
+
351
+
352
+ def _terminal_name(node: ast.expr) -> str | None:
353
+ match node:
354
+ case ast.Name():
355
+ return node.id
356
+ case ast.Attribute():
357
+ return node.attr
358
+ case _:
359
+ return None
360
+
361
+
362
+ def _record_docstring_use(node: ast.AST, consumed: set[str], aliases: dict[str, set[str]]) -> None:
363
+ if isinstance(node, ast.Attribute) and node.attr == "__doc__":
364
+ if name := _terminal_name(node.value):
365
+ consumed.add(name)
366
+ elif isinstance(node, ast.Call) and _is_docstring_reader(node):
367
+ if name := _terminal_name(node.args[0]):
368
+ consumed.add(name)
369
+ elif isinstance(node, ast.Subscript):
370
+ if name := _subscripted_docstring_owner(node):
371
+ consumed.add(name)
372
+ else:
373
+ _record_docstring_alias(node, aliases)
374
+
375
+
376
+ def _subscripted_docstring_owner(node: ast.Subscript) -> str | None:
377
+ if not isinstance(node.slice, ast.Constant) or node.slice.value != "__doc__":
378
+ return None
379
+ value = node.value
380
+ if isinstance(value, ast.Attribute) and value.attr == "__dict__":
381
+ return _terminal_name(value.value)
382
+ if isinstance(value, ast.Call) and isinstance(value.func, ast.Name) and value.func.id == "vars" and value.args:
383
+ return _terminal_name(value.args[0])
384
+ return None
385
+
386
+
387
+ def _is_docstring_reader(node: ast.Call) -> bool:
388
+ if not node.args:
389
+ return False
390
+ function = node.func
391
+ if isinstance(function, ast.Name) and function.id == "help":
392
+ return True
393
+ if isinstance(function, ast.Attribute) and function.attr in {"getdoc", "render_doc"}:
394
+ return True
395
+ return (
396
+ isinstance(function, ast.Name)
397
+ and function.id == "getattr"
398
+ and len(node.args) >= _GETATTR_MIN_ARGS
399
+ and isinstance(node.args[1], ast.Constant)
400
+ and node.args[1].value == "__doc__"
401
+ )
402
+
403
+
404
+ def _record_docstring_alias(node: ast.AST, aliases: dict[str, set[str]]) -> None:
405
+ if isinstance(node, ast.Assign) and isinstance(node.value, (ast.Name, ast.Attribute)):
406
+ original = _terminal_name(node.value)
407
+ for target in node.targets:
408
+ if isinstance(target, ast.Name) and original is not None:
409
+ aliases.setdefault(target.id, set()).add(original)
410
+ elif (
411
+ isinstance(node, ast.AnnAssign)
412
+ and isinstance(node.target, ast.Name)
413
+ and isinstance(node.value, (ast.Name, ast.Attribute))
414
+ ):
415
+ original = _terminal_name(node.value)
416
+ if original is not None:
417
+ aliases.setdefault(node.target.id, set()).add(original)
@@ -17,7 +17,6 @@ from sarj_python_lint.rule_base import (
17
17
  Severity,
18
18
  is_suppressed,
19
19
  )
20
- from sarj_python_lint.rules._ast_index import walk as walk_ast
21
20
  from sarj_python_lint.rules._comments import is_protected, stem
22
21
  from sarj_python_lint.rules._docstrings import (
23
22
  VALUE_MARKER_RE,
@@ -27,11 +26,9 @@ from sarj_python_lint.rules._docstrings import (
27
26
 
28
27
  if TYPE_CHECKING:
29
28
  from sarj_python_lint._file_context import PythonFileContext
30
- from sarj_python_lint.rules._ast_index import NodeIndex
31
29
 
32
30
 
33
31
  _GRAMMATICAL_FILLER = frozenset({"a", "an", "class", "the"})
34
- _GETATTR_MIN_ARGS = 2
35
32
  _DOCSTRING_TOKEN_RE = re.compile(r"[^\W\d_]+(?:'[^\W\d_]+)?|\d+")
36
33
 
37
34
 
@@ -93,7 +90,7 @@ class RedundantClassDocstring(Rule):
93
90
  if tree is None:
94
91
  return []
95
92
  source_lines = context.source_lines
96
- consumed_docstrings = _consumed_docstring_names(tree, node_index=context.node_index)
93
+ consumed_docstrings = context.consumed_docstring_names
97
94
  diags: list[Diagnostic] = []
98
95
  for node in context.nodes(ast.ClassDef):
99
96
  if node.name not in consumed_docstrings and self._is_ceremony(node):
@@ -128,88 +125,3 @@ class RedundantClassDocstring(Rule):
128
125
  if (word := match.group(0).lower()) not in _GRAMMATICAL_FILLER
129
126
  ]
130
127
  return bool(content) and all(stem(word) in known for word in content)
131
-
132
-
133
- def _consumed_docstring_names(tree: ast.Module, *, node_index: NodeIndex | None = None) -> set[str]:
134
- consumed: set[str] = set()
135
- aliases: dict[str, set[str]] = {}
136
- for node in walk_ast(tree, index=node_index):
137
- _record_docstring_use(node, consumed, aliases)
138
- changed = True
139
- while changed:
140
- changed = False
141
- for alias, originals in aliases.items():
142
- if alias not in consumed:
143
- continue
144
- before = len(consumed)
145
- consumed.update(originals)
146
- changed |= len(consumed) != before
147
- return consumed
148
-
149
-
150
- def _terminal_name(node: ast.expr) -> str | None:
151
- match node:
152
- case ast.Name():
153
- return node.id
154
- case ast.Attribute():
155
- return node.attr
156
- case _:
157
- return None
158
-
159
-
160
- def _record_docstring_use(node: ast.AST, consumed: set[str], aliases: dict[str, set[str]]) -> None:
161
- if isinstance(node, ast.Attribute) and node.attr == "__doc__":
162
- if name := _terminal_name(node.value):
163
- consumed.add(name)
164
- elif isinstance(node, ast.Call) and _is_docstring_reader(node):
165
- if name := _terminal_name(node.args[0]):
166
- consumed.add(name)
167
- elif isinstance(node, ast.Subscript):
168
- if name := _subscripted_docstring_owner(node):
169
- consumed.add(name)
170
- else:
171
- _record_docstring_alias(node, aliases)
172
-
173
-
174
- def _subscripted_docstring_owner(node: ast.Subscript) -> str | None:
175
- if not isinstance(node.slice, ast.Constant) or node.slice.value != "__doc__":
176
- return None
177
- value = node.value
178
- if isinstance(value, ast.Attribute) and value.attr == "__dict__":
179
- return _terminal_name(value.value)
180
- if isinstance(value, ast.Call) and isinstance(value.func, ast.Name) and value.func.id == "vars" and value.args:
181
- return _terminal_name(value.args[0])
182
- return None
183
-
184
-
185
- def _is_docstring_reader(node: ast.Call) -> bool:
186
- if not node.args:
187
- return False
188
- function = node.func
189
- if isinstance(function, ast.Name) and function.id == "help":
190
- return True
191
- if isinstance(function, ast.Attribute) and function.attr in {"getdoc", "render_doc"}:
192
- return True
193
- return (
194
- isinstance(function, ast.Name)
195
- and function.id == "getattr"
196
- and len(node.args) >= _GETATTR_MIN_ARGS
197
- and isinstance(node.args[1], ast.Constant)
198
- and node.args[1].value == "__doc__"
199
- )
200
-
201
-
202
- def _record_docstring_alias(node: ast.AST, aliases: dict[str, set[str]]) -> None:
203
- if isinstance(node, ast.Assign) and isinstance(node.value, (ast.Name, ast.Attribute)):
204
- original = _terminal_name(node.value)
205
- for target in node.targets:
206
- if isinstance(target, ast.Name) and original is not None:
207
- aliases.setdefault(target.id, set()).add(original)
208
- elif (
209
- isinstance(node, ast.AnnAssign)
210
- and isinstance(node.target, ast.Name)
211
- and isinstance(node.value, (ast.Name, ast.Attribute))
212
- ):
213
- original = _terminal_name(node.value)
214
- if original is not None:
215
- aliases.setdefault(node.target.id, set()).add(original)
@@ -18,7 +18,7 @@ from sarj_python_lint.rule_base import (
18
18
  Severity,
19
19
  is_suppressed,
20
20
  )
21
- from sarj_python_lint.rules._ast_index import children, walk as walk_ast
21
+ from sarj_python_lint.rules._ast_index import children
22
22
  from sarj_python_lint.rules._comments import is_protected, split_identifier, stem
23
23
  from sarj_python_lint.rules._docstrings import (
24
24
  VALUE_MARKER_RE,
@@ -28,12 +28,10 @@ from sarj_python_lint.rules._docstrings import (
28
28
 
29
29
  if TYPE_CHECKING:
30
30
  from sarj_python_lint._file_context import PythonFileContext
31
- from sarj_python_lint.rules._ast_index import NodeIndex
32
31
 
33
32
 
34
33
  _DOCSTRING_TOKEN_RE = re.compile(r"[^\W\d_]+(?:'[^\W\d_]+)?|\d+")
35
34
  _GRAMMATICAL_FILLER = frozenset({"a", "an", "function", "method", "the"})
36
- _GETATTR_MIN_ARGS = 2
37
35
  _MULTI_PARAMETER_MIN = 2
38
36
 
39
37
 
@@ -41,7 +39,7 @@ _MULTI_PARAMETER_MIN = 2
41
39
  class _ScanContext:
42
40
  path: Path
43
41
  source_lines: list[str]
44
- consumed_docstrings: set[str]
42
+ consumed_docstrings: frozenset[str]
45
43
  diagnostics: list[Diagnostic]
46
44
 
47
45
 
@@ -105,7 +103,7 @@ class RedundantDocstring(Rule):
105
103
  if tree is None:
106
104
  return []
107
105
  source_lines = context.source_lines
108
- consumed_docstrings = _consumed_docstring_names(tree, node_index=context.node_index)
106
+ consumed_docstrings = context.consumed_docstring_names
109
107
  diags: list[Diagnostic] = []
110
108
  analysis_context = _ScanContext(path, source_lines, consumed_docstrings, diags)
111
109
  self._walk(tree, analysis_context)
@@ -190,88 +188,3 @@ def _parameters_are_distinguished(groups: list[set[str]], content: set[str]) ->
190
188
  if not distinguishing or distinguishing.isdisjoint(content):
191
189
  return False
192
190
  return True
193
-
194
-
195
- def _consumed_docstring_names(tree: ast.Module, *, node_index: NodeIndex | None = None) -> set[str]:
196
- consumed: set[str] = set()
197
- aliases: dict[str, set[str]] = {}
198
- for node in walk_ast(tree, index=node_index):
199
- _record_docstring_use(node, consumed, aliases)
200
- changed = True
201
- while changed:
202
- changed = False
203
- for alias, originals in aliases.items():
204
- if alias not in consumed:
205
- continue
206
- before = len(consumed)
207
- consumed.update(originals)
208
- changed |= len(consumed) != before
209
- return consumed
210
-
211
-
212
- def _terminal_name(node: ast.expr) -> str | None:
213
- match node:
214
- case ast.Name():
215
- return node.id
216
- case ast.Attribute():
217
- return node.attr
218
- case _:
219
- return None
220
-
221
-
222
- def _record_docstring_use(node: ast.AST, consumed: set[str], aliases: dict[str, set[str]]) -> None:
223
- if isinstance(node, ast.Attribute) and node.attr == "__doc__":
224
- if name := _terminal_name(node.value):
225
- consumed.add(name)
226
- elif isinstance(node, ast.Call) and _is_docstring_reader(node):
227
- if name := _terminal_name(node.args[0]):
228
- consumed.add(name)
229
- elif isinstance(node, ast.Subscript):
230
- if name := _subscripted_docstring_owner(node):
231
- consumed.add(name)
232
- else:
233
- _record_docstring_alias(node, aliases)
234
-
235
-
236
- def _subscripted_docstring_owner(node: ast.Subscript) -> str | None:
237
- if not isinstance(node.slice, ast.Constant) or node.slice.value != "__doc__":
238
- return None
239
- value = node.value
240
- if isinstance(value, ast.Attribute) and value.attr == "__dict__":
241
- return _terminal_name(value.value)
242
- if isinstance(value, ast.Call) and isinstance(value.func, ast.Name) and value.func.id == "vars" and value.args:
243
- return _terminal_name(value.args[0])
244
- return None
245
-
246
-
247
- def _is_docstring_reader(node: ast.Call) -> bool:
248
- if not node.args:
249
- return False
250
- function = node.func
251
- if isinstance(function, ast.Name) and function.id == "help":
252
- return True
253
- if isinstance(function, ast.Attribute) and function.attr in {"getdoc", "render_doc"}:
254
- return True
255
- return (
256
- isinstance(function, ast.Name)
257
- and function.id == "getattr"
258
- and len(node.args) >= _GETATTR_MIN_ARGS
259
- and isinstance(node.args[1], ast.Constant)
260
- and node.args[1].value == "__doc__"
261
- )
262
-
263
-
264
- def _record_docstring_alias(node: ast.AST, aliases: dict[str, set[str]]) -> None:
265
- if isinstance(node, ast.Assign) and isinstance(node.value, (ast.Name, ast.Attribute)):
266
- original = _terminal_name(node.value)
267
- for target in node.targets:
268
- if isinstance(target, ast.Name) and original is not None:
269
- aliases.setdefault(target.id, set()).add(original)
270
- elif (
271
- isinstance(node, ast.AnnAssign)
272
- and isinstance(node.target, ast.Name)
273
- and isinstance(node.value, (ast.Name, ast.Attribute))
274
- ):
275
- original = _terminal_name(node.value)
276
- if original is not None:
277
- aliases.setdefault(node.target.id, set()).add(original)