sarj-python-lint 1.16.1__tar.gz → 1.16.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/PKG-INFO +1 -1
  2. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/pyproject.toml +1 -1
  3. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_broad_keyword_capture.py +123 -21
  4. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/.gitignore +0 -0
  5. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/LICENSE +0 -0
  6. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/README.md +0 -0
  7. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/__init__.py +0 -0
  8. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/__main__.py +0 -0
  9. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/_analysis_session.py +0 -0
  10. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/_file_context.py +0 -0
  11. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/_filesystem.py +0 -0
  12. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/_python_target.py +0 -0
  13. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/_ratchet_cli.py +0 -0
  14. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/_secret_names.py +0 -0
  15. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/_version.py +0 -0
  16. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/benchmark.py +0 -0
  17. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/json_boundary.py +0 -0
  18. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/py.typed +0 -0
  19. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/ratchet.py +0 -0
  20. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rule_base.py +0 -0
  21. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/__init__.py +0 -0
  22. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
  23. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_ast_index.py +0 -0
  24. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_ast_position.py +0 -0
  25. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_comments.py +0 -0
  26. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
  27. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
  28. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_docstrings.py +0 -0
  29. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_fastapi.py +0 -0
  30. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_first_party.py +0 -0
  31. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
  32. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_imports.py +0 -0
  33. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_local_source.py +0 -0
  34. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_logging.py +0 -0
  35. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
  36. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_paths.py +0 -0
  37. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_project_index.py +0 -0
  38. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
  39. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_pytest.py +0 -0
  40. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_registry.py +0 -0
  41. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
  42. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_set_fields.py +0 -0
  43. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_sql.py +0 -0
  44. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
  45. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
  46. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/_test_composition.py +0 -0
  47. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
  48. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
  49. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
  50. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
  51. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/discourage_nullable_constructor_parameters.py +0 -0
  52. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
  53. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
  54. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
  55. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
  56. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
  57. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
  58. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
  59. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
  60. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
  61. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
  62. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
  63. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
  64. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
  65. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
  66. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
  67. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
  68. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
  69. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
  70. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
  71. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
  72. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
  73. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
  74. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
  75. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
  76. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
  77. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
  78. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
  79. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
  80. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
  81. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
  82. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
  83. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
  84. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
  85. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
  86. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
  87. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
  88. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
  89. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
  90. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
  91. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
  92. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
  93. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
  94. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
  95. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
  96. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
  97. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_select_star.py +0 -0
  98. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
  99. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
  100. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
  101. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
  102. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
  103. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
  104. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
  105. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
  106. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +0 -0
  107. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
  108. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
  109. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
  110. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
  111. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
  112. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
  113. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +0 -0
  114. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
  115. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
  116. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
  117. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
  118. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
  119. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
  120. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
  121. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
  122. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
  123. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
  124. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
  125. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
  126. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
  127. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
  128. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
  129. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
  130. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
  131. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
  132. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
  133. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +0 -0
  134. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
  135. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
  136. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
  137. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
  138. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
  139. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
  140. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
  141. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
  142. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
  143. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
  144. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
  145. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
  146. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
  147. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
  148. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
  149. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
  150. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
  151. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
  152. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
  153. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
  154. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
  155. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
  156. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
  157. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
  158. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/require_precise_factory_signature.py +0 -0
  159. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
  160. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
  161. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
  162. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
  163. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
  164. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
  165. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/stepdown.py +0 -0
  166. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
  167. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
  168. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
  169. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
  170. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
  171. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
  172. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
  173. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
  174. {sarj_python_lint-1.16.1 → sarj_python_lint-1.16.2}/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.16.1
3
+ Version: 1.16.2
4
4
  Summary: Custom Python lint rules — AST-based, pre-commit-friendly, hypermodern defaults
5
5
  Project-URL: Homepage, https://code-standards.sarj.ai/rules/python/
6
6
  Project-URL: Documentation, https://code-standards.sarj.ai/rules/python/
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sarj-python-lint"
3
- version = "1.16.1"
3
+ version = "1.16.2"
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" }]
@@ -1,7 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import ast
4
+ from dataclasses import replace
4
5
  from pathlib import PurePosixPath
6
+ from types import MappingProxyType
5
7
  from typing import TYPE_CHECKING, ClassVar, final
6
8
 
7
9
  from sarj_python_lint.rule_base import (
@@ -18,6 +20,7 @@ from sarj_python_lint.rule_base import (
18
20
  )
19
21
  from sarj_python_lint.rules._annotation_semantics import AnnotationSemantics, scope_bound_names
20
22
  from sarj_python_lint.rules._ast_index import walk
23
+ from sarj_python_lint.rules.no_hidden_constructor_fallback import LocalBindingCollector, scope_bindings
21
24
 
22
25
 
23
26
  if TYPE_CHECKING:
@@ -62,7 +65,7 @@ class NoBroadKeywordCapture(Rule):
62
65
  "Reports missing, Any- or object-valued keyword captures whether discarded, read or forwarded.",
63
66
  "Precise or unresolved decorated signature-declaration families and functions with unresolved decorator effects are excluded; known classmethod/staticmethod/abstractmethod/final/override declarations remain eligible.",
64
67
  "Homogeneous keyword types constrain values but allow arbitrary names; ParamSpec preserves only its target's existing contract.",
65
- "Generated/vendor source and stubs are excluded. Unresolved imports, wildcard imports and shadowed annotation provenance are conservative.",
68
+ "Generated/vendor source and stubs are excluded. Unresolved imports, wildcard imports, conflicting imports, actual global or definition-time writes and shadowed annotation provenance are conservative. Identical imports and read-only global declarations remain eligible.",
66
69
  "Cross-file aliases, external stubs, generated signatures and runtime reflection are not resolved; transparent annotation metadata and ambiguous decorated declaration families can cause conservative false negatives.",
67
70
  "No autofix can infer the intended contract. Dynamic payload/formatting APIs can intentionally need an exact-code exception.",
68
71
  ),
@@ -165,7 +168,8 @@ class NoBroadKeywordCapture(Rule):
165
168
  tree = context.tree
166
169
  if tree is None:
167
170
  return []
168
- semantics = AnnotationSemantics.from_tree(tree)
171
+ semantics = _stable_annotation_semantics(context, tree)
172
+ mutated_members = _mutated_annotation_members(context, semantics)
169
173
  overloads: set[ast.FunctionDef | ast.AsyncFunctionDef] | None = None
170
174
  findings: list[Diagnostic] = []
171
175
  for function in context.nodes(ast.FunctionDef, ast.AsyncFunctionDef):
@@ -174,12 +178,12 @@ class NoBroadKeywordCapture(Rule):
174
178
  continue
175
179
  if not _is_broad(argument.annotation, semantics):
176
180
  continue
177
- if _uncertain_annotation(argument.annotation, function, context, semantics):
181
+ if _uncertain_annotation(argument.annotation, function, context, semantics, mutated_members):
178
182
  continue
179
- if _unknown_decorator(function, context, semantics):
183
+ if _unknown_decorator(function, context, semantics, mutated_members):
180
184
  continue
181
185
  if overloads is None:
182
- overloads = _overload_implementations(context, semantics)
186
+ overloads = _overload_implementations(context, semantics, mutated_members)
183
187
  if function in overloads:
184
188
  continue
185
189
  if is_suppressed(context.source_lines, argument.lineno, self.code) or is_suppressed(
@@ -202,6 +206,90 @@ class NoBroadKeywordCapture(Rule):
202
206
  return sorted(findings, key=lambda finding: (finding.line, finding.col))
203
207
 
204
208
 
209
+ def _stable_annotation_semantics(context: PythonFileContext, tree: ast.Module) -> AnnotationSemantics:
210
+ semantics = AnnotationSemantics.from_tree(tree)
211
+ unstable = _conflicting_annotation_imports(context, semantics) | _annotation_binding_writes(context)
212
+ if not unstable:
213
+ return semantics
214
+ imports = replace(
215
+ semantics.imports,
216
+ bindings=MappingProxyType(
217
+ {name: target for name, target in semantics.imports.bindings.items() if name not in unstable}
218
+ ),
219
+ shadowed_names=semantics.imports.shadowed_names | unstable,
220
+ )
221
+ return replace(
222
+ semantics,
223
+ imports=imports,
224
+ aliases=MappingProxyType({name: value for name, value in semantics.aliases.items() if name not in unstable}),
225
+ )
226
+
227
+
228
+ def _conflicting_annotation_imports(context: PythonFileContext, semantics: AnnotationSemantics) -> set[str]:
229
+ conflicts: set[str] = set()
230
+ for statement in context.nodes(ast.Import, ast.ImportFrom):
231
+ if not isinstance(_lexical_scope(statement, context), ast.Module):
232
+ continue
233
+ for alias in statement.names:
234
+ name = alias.asname or alias.name.partition(".")[0]
235
+ binding = semantics.imports.bindings.get(name)
236
+ if binding is not None and _import_reference(statement, alias) != (binding.module, binding.symbol):
237
+ conflicts.add(name)
238
+ return conflicts
239
+
240
+
241
+ def _import_reference(statement: ast.Import | ast.ImportFrom, alias: ast.alias) -> tuple[str, str | None] | None:
242
+ if isinstance(statement, ast.ImportFrom):
243
+ return (statement.module, alias.name) if not statement.level and statement.module is not None else None
244
+ return (alias.name if alias.asname else alias.name.partition(".")[0], None)
245
+
246
+
247
+ def _annotation_binding_writes(context: PythonFileContext) -> set[str]:
248
+ writes: set[str] = set()
249
+ for owner in context.nodes(ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef, ast.Lambda):
250
+ if isinstance(_lexical_scope(owner, context), ast.Module):
251
+ header = LocalBindingCollector()
252
+ header.visit(owner)
253
+ if not isinstance(owner, ast.Lambda):
254
+ header.names.discard(owner.name)
255
+ writes.update(header.names)
256
+ if not isinstance(owner, ast.Lambda):
257
+ body = LocalBindingCollector()
258
+ for statement in owner.body:
259
+ body.visit(statement)
260
+ writes.update(body.names & body.globals)
261
+ return writes
262
+
263
+
264
+ def _mutated_annotation_members(context: PythonFileContext, semantics: AnnotationSemantics) -> frozenset[str]:
265
+ members: set[str] = set()
266
+ for node in context.nodes(ast.Attribute):
267
+ if not isinstance(node.ctx, (ast.Store, ast.Del)) or _shadowed_annotation(node, node, context, semantics):
268
+ continue
269
+ qualified = semantics.imports.resolved_qualified_name(node)
270
+ if qualified is not None:
271
+ members.add(qualified)
272
+ return frozenset(members)
273
+
274
+
275
+ def _uses_mutated_member(annotation: ast.expr, semantics: AnnotationSemantics, mutated_members: frozenset[str]) -> bool:
276
+ if not mutated_members:
277
+ return False
278
+ pending = [annotation]
279
+ seen: set[str] = set()
280
+ while pending:
281
+ parsed = semantics.parse(pending.pop())
282
+ if parsed is None:
283
+ continue
284
+ for node in walk(parsed):
285
+ if isinstance(node, ast.Attribute) and semantics.imports.resolved_qualified_name(node) in mutated_members:
286
+ return True
287
+ if isinstance(node, ast.Name) and node.id in semantics.aliases and node.id not in seen:
288
+ seen.add(node.id)
289
+ pending.append(semantics.aliases[node.id])
290
+ return False
291
+
292
+
205
293
  def _is_broad(annotation: ast.expr | None, semantics: AnnotationSemantics) -> bool:
206
294
  if annotation is None:
207
295
  return True
@@ -215,29 +303,35 @@ def _is_broad(annotation: ast.expr | None, semantics: AnnotationSemantics) -> bo
215
303
 
216
304
  def _shadowed_annotation(
217
305
  annotation: ast.expr | None,
218
- function: ast.FunctionDef | ast.AsyncFunctionDef,
306
+ function: ast.AST,
219
307
  context: PythonFileContext,
220
308
  semantics: AnnotationSemantics,
221
309
  ) -> bool:
222
310
  names = _uses_names(annotation, semantics)
223
- if names & _type_parameter_names(function):
311
+ if isinstance(function, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)) and names & _type_parameter_names(
312
+ function
313
+ ):
224
314
  return True
225
315
  parent = context.parents.get(function)
226
316
  while parent is not None:
227
- if isinstance(parent, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)) and names & _scope_bindings(
228
- parent
229
- ):
317
+ if isinstance(
318
+ parent, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef, ast.Lambda)
319
+ ) and names & _scope_bindings(parent):
230
320
  return True
231
321
  parent = context.parents.get(parent)
232
322
  return False
233
323
 
234
324
 
235
- def _scope_bindings(owner: ast.FunctionDef | ast.AsyncFunctionDef | ast.ClassDef) -> set[str]:
236
- bound = scope_bound_names(owner.body) | _type_parameter_names(owner)
237
- if isinstance(owner, (ast.FunctionDef, ast.AsyncFunctionDef)):
238
- args = owner.args
239
- bound.update(arg.arg for arg in [*args.posonlyargs, *args.args, *args.kwonlyargs])
240
- bound.update(arg.arg for arg in (args.vararg, args.kwarg) if arg is not None)
325
+ def _scope_bindings(owner: ast.FunctionDef | ast.AsyncFunctionDef | ast.ClassDef | ast.Lambda) -> set[str]:
326
+ if isinstance(owner, (ast.FunctionDef, ast.AsyncFunctionDef, ast.Lambda)):
327
+ bound = set(scope_bindings(owner))
328
+ else:
329
+ collector = LocalBindingCollector()
330
+ for statement in owner.body:
331
+ collector.visit(statement)
332
+ bound = collector.names - collector.globals
333
+ if not isinstance(owner, ast.Lambda):
334
+ bound.update(_type_parameter_names(owner))
241
335
  return bound
242
336
 
243
337
 
@@ -250,10 +344,11 @@ def _uncertain_annotation(
250
344
  function: ast.FunctionDef | ast.AsyncFunctionDef,
251
345
  context: PythonFileContext,
252
346
  semantics: AnnotationSemantics,
347
+ mutated_members: frozenset[str],
253
348
  ) -> bool:
254
349
  if annotation is None:
255
350
  return False
256
- if _has_wildcard_import(context):
351
+ if _has_wildcard_import(context) or _uses_mutated_member(annotation, semantics, mutated_members):
257
352
  return True
258
353
  if context.tree is not None:
259
354
  unknown = scope_bound_names(context.tree.body) - set(semantics.imports.bindings) - set(semantics.aliases)
@@ -280,8 +375,9 @@ def _known_decorator(
280
375
  function: ast.FunctionDef | ast.AsyncFunctionDef,
281
376
  context: PythonFileContext,
282
377
  semantics: AnnotationSemantics,
378
+ mutated_members: frozenset[str],
283
379
  ) -> str | None:
284
- if _has_wildcard_import(context):
380
+ if _has_wildcard_import(context) or _uses_mutated_member(decorator, semantics, mutated_members):
285
381
  return None
286
382
  if _shadowed_annotation(decorator, function, context, semantics):
287
383
  return None
@@ -297,9 +393,10 @@ def _unknown_decorator(
297
393
  function: ast.FunctionDef | ast.AsyncFunctionDef,
298
394
  context: PythonFileContext,
299
395
  semantics: AnnotationSemantics,
396
+ mutated_members: frozenset[str],
300
397
  ) -> bool:
301
398
  return any(
302
- _known_decorator(decorator, function, context, semantics) not in _KNOWN_DECORATORS
399
+ _known_decorator(decorator, function, context, semantics, mutated_members) not in _KNOWN_DECORATORS
303
400
  for decorator in function.decorator_list
304
401
  )
305
402
 
@@ -307,6 +404,7 @@ def _unknown_decorator(
307
404
  def _overload_implementations(
308
405
  context: PythonFileContext,
309
406
  semantics: AnnotationSemantics,
407
+ mutated_members: frozenset[str],
310
408
  ) -> set[ast.FunctionDef | ast.AsyncFunctionDef]:
311
409
  families: dict[tuple[ast.AST | None, str], list[ast.FunctionDef | ast.AsyncFunctionDef]] = {}
312
410
  implementations: set[ast.FunctionDef | ast.AsyncFunctionDef] = set()
@@ -315,7 +413,7 @@ def _overload_implementations(
315
413
  scope = _lexical_scope(node, context)
316
414
  if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
317
415
  key = scope, node.name
318
- if _signature_declaration(node, context, semantics):
416
+ if _signature_declaration(node, context, semantics, mutated_members):
319
417
  families.setdefault(key, []).append(node)
320
418
  else:
321
419
  family = families.pop(key, [])
@@ -356,6 +454,10 @@ def _signature_declaration(
356
454
  function: ast.FunctionDef | ast.AsyncFunctionDef,
357
455
  context: PythonFileContext,
358
456
  semantics: AnnotationSemantics,
457
+ mutated_members: frozenset[str],
359
458
  ) -> bool:
360
- decorators = {_known_decorator(decorator, function, context, semantics) for decorator in function.decorator_list}
459
+ decorators = {
460
+ _known_decorator(decorator, function, context, semantics, mutated_members)
461
+ for decorator in function.decorator_list
462
+ }
361
463
  return bool(decorators & _OVERLOAD_DECORATORS) or not decorators <= _KNOWN_DECORATORS