sarj-python-lint 1.95.0__tar.gz → 1.97.0__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 (313) hide show
  1. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/PKG-INFO +1 -1
  2. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/pyproject.toml +1 -1
  3. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_native_object_contracts.py +9 -7
  4. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_project_index.py +132 -1
  5. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +17 -5
  6. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_custom_control_flow_exception.py +25 -11
  7. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_discarded_tagged_outcome.py +50 -1
  8. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +90 -29
  9. sarj_python_lint-1.97.0/src/sarj_python_lint/rules/no_recording_store.py +491 -0
  10. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_redundant_sql_alias.py +8 -1
  11. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_application_model_joins.py +26 -13
  12. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +150 -76
  13. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_optional_composite.py +47 -21
  14. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_precise_object_contract.py +9 -40
  15. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/store_insert_requires_explicit_conflict_policy.py +37 -11
  16. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/store_mutation_command_fanout.py +84 -16
  17. sarj_python_lint-1.95.0/src/sarj_python_lint/rules/no_recording_store.py +0 -276
  18. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/.gitignore +0 -0
  19. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/LICENSE +0 -0
  20. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/README.md +0 -0
  21. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/__init__.py +0 -0
  22. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/__main__.py +0 -0
  23. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_analysis_session.py +0 -0
  24. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_autofix.py +0 -0
  25. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_autofix_aliases.py +0 -0
  26. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_autofix_annotations.py +0 -0
  27. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_autofix_comments.py +0 -0
  28. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_autofix_declared_contracts.py +0 -0
  29. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_autofix_declared_tests.py +0 -0
  30. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_autofix_docs.py +0 -0
  31. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_autofix_enums.py +0 -0
  32. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_autofix_exhaustiveness.py +0 -0
  33. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_autofix_inert.py +0 -0
  34. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_autofix_parameters.py +0 -0
  35. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_autofix_repeated.py +0 -0
  36. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_autofix_security.py +0 -0
  37. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_autofix_sql_projection.py +0 -0
  38. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_autofix_tests.py +0 -0
  39. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_file_context.py +0 -0
  40. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_filesystem.py +0 -0
  41. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_fixes.py +0 -0
  42. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_parallel.py +0 -0
  43. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_prepared_sources.py +0 -0
  44. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_python_target.py +0 -0
  45. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_ratchet_cli.py +0 -0
  46. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_rule_descriptors.py +0 -0
  47. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_secret_names.py +0 -0
  48. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_source.py +0 -0
  49. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/_version.py +0 -0
  50. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/application_logging.py +0 -0
  51. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/autofix.py +0 -0
  52. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/benchmark.py +0 -0
  53. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/cast_access.py +0 -0
  54. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/interpreter_argv.py +0 -0
  55. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/json_boundary.py +0 -0
  56. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/py.typed +0 -0
  57. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/ratchet.py +0 -0
  58. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rule_base.py +0 -0
  59. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rule_metadata.py +0 -0
  60. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/__init__.py +0 -0
  61. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_annotation_origins.py +0 -0
  62. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
  63. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_ast_index.py +0 -0
  64. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_ast_names.py +0 -0
  65. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_ast_position.py +0 -0
  66. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_async_lifecycle.py +0 -0
  67. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_binding_inventory.py +0 -0
  68. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_closed_helpers.py +0 -0
  69. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_comment_narration.py +0 -0
  70. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_comments.py +0 -0
  71. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
  72. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_copy_on_write.py +0 -0
  73. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_data_union_discriminator.py +0 -0
  74. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_declared_contracts.py +0 -0
  75. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
  76. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_docstrings.py +0 -0
  77. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_exports.py +0 -0
  78. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_fastapi.py +0 -0
  79. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_first_party.py +0 -0
  80. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
  81. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_imports.py +0 -0
  82. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_inert_model_annotation.py +0 -0
  83. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_inherited_contract.py +0 -0
  84. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_local_alias_fix.py +0 -0
  85. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_local_source.py +0 -0
  86. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_logging.py +0 -0
  87. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_mapping_shape_callbacks.py +0 -0
  88. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_namespace_access.py +0 -0
  89. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_native_namespace_capability.py +0 -0
  90. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
  91. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_numeric_proof.py +0 -0
  92. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_opaque_contracts.py +0 -0
  93. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_paths.py +0 -0
  94. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_postgres.py +0 -0
  95. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
  96. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_pydantic_field_contract.py +0 -0
  97. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_pytest.py +0 -0
  98. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_registry.py +0 -0
  99. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_resolved_operation_signature.py +0 -0
  100. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
  101. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_route_shapes.py +0 -0
  102. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_runtime_bindings.py +0 -0
  103. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_runtime_registry.py +0 -0
  104. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_service_http_callbacks.py +0 -0
  105. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_set_fields.py +0 -0
  106. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_sql.py +0 -0
  107. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_sql_aggregate_identity.py +0 -0
  108. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_sql_explain.py +0 -0
  109. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_sql_policy_source.py +0 -0
  110. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_static_json_alias.py +0 -0
  111. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_store_sql.py +0 -0
  112. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_store_writes.py +0 -0
  113. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
  114. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
  115. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_test_composition.py +0 -0
  116. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_test_provenance.py +0 -0
  117. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_transactional_sql.py +0 -0
  118. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/_type_guard_symbols.py +0 -0
  119. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
  120. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/async_executor_shutdown.py +0 -0
  121. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
  122. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/async_subprocess_cancellation_cleanup.py +0 -0
  123. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/cancel_owned_task_without_join.py +0 -0
  124. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
  125. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/delete_route_returns_no_content.py +0 -0
  126. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
  127. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
  128. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/duplicate_adjacent_exception_handler.py +0 -0
  129. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/duplicate_closed_pure_helper.py +0 -0
  130. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/duplicate_pytest_fixture_params.py +0 -0
  131. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
  132. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/failed_probe_zero_threshold.py +0 -0
  133. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
  134. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
  135. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
  136. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
  137. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
  138. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
  139. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
  140. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/nan_hidden_by_builtin_min.py +0 -0
  141. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
  142. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
  143. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
  144. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_async_client_in_constructor.py +0 -0
  145. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_async_function_cache.py +0 -0
  146. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_before_validator_input_mutation.py +0 -0
  147. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_blanket_suppression.py +0 -0
  148. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_broad_keyword_capture.py +0 -0
  149. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
  150. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_conflicting_pydantic_alias_validation.py +0 -0
  151. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
  152. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_contradictory_type_guard.py +0 -0
  153. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
  154. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
  155. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_create_verb_in_post_path.py +0 -0
  156. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
  157. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_defaulted_environment_setting.py +0 -0
  158. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
  159. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_discarded_validation_result.py +0 -0
  160. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_dual_shape_model_field_reader.py +0 -0
  161. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
  162. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
  163. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_duplicate_field_validator_body.py +0 -0
  164. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_exception_text_in_500_detail.py +0 -0
  165. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
  166. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
  167. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
  168. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
  169. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
  170. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_fixed_sleep_in_loop.py +0 -0
  171. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_folded_bad_request_not_found.py +0 -0
  172. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
  173. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_generic_json_parser.py +0 -0
  174. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
  175. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_hasattr.py +0 -0
  176. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
  177. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_impossible_pydantic_field_bounds.py +0 -0
  178. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
  179. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_input_model_mutation.py +0 -0
  180. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_interpreter_source_arguments.py +0 -0
  181. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
  182. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_invalid_pydantic_bypass.py +0 -0
  183. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_invalid_pydantic_validator_return.py +0 -0
  184. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_loguru_exc_info.py +0 -0
  185. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_loguru_printf_format.py +0 -0
  186. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_mocked_pydantic_value_object.py +0 -0
  187. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_mutating_container_transform.py +0 -0
  188. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_mutating_input_with_result.py +0 -0
  189. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
  190. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
  191. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
  192. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_partial_type_is.py +0 -0
  193. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
  194. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
  195. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
  196. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
  197. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_redundant_attribute_unpacking.py +0 -0
  198. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
  199. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_redundant_local_alias.py +0 -0
  200. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
  201. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
  202. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
  203. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
  204. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
  205. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_select_star.py +0 -0
  206. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
  207. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
  208. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_shallow_record_type_guard.py +0 -0
  209. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_slash_collection_root_under_prefix.py +0 -0
  210. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
  211. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
  212. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
  213. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_test_comments.py +0 -0
  214. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_test_method_grafting.py +0 -0
  215. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
  216. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
  217. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_unknown_pydantic_validator_field.py +0 -0
  218. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
  219. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_unused_copy_result.py +0 -0
  220. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +0 -0
  221. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
  222. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
  223. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
  224. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/no_work_verb_get_route.py +0 -0
  225. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
  226. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
  227. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
  228. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +0 -0
  229. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_bulk_upsert.py +0 -0
  230. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
  231. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
  232. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
  233. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_declarative_batch_validation.py +0 -0
  234. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_direct_import_module.py +0 -0
  235. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_discriminated_model_union.py +0 -0
  236. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
  237. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_grouped_settings.py +0 -0
  238. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
  239. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
  240. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
  241. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
  242. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
  243. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
  244. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
  245. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
  246. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
  247. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
  248. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_native_string_check.py +0 -0
  249. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
  250. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
  251. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
  252. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_psycopg_executemany.py +0 -0
  253. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
  254. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_pydantic_model_assertion.py +0 -0
  255. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_pytest_dependency_fixtures.py +0 -0
  256. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_pytest_fixture_contract.py +0 -0
  257. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +0 -0
  258. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
  259. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_required_constructor_parameters.py +0 -0
  260. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_runtime_validation.py +0 -0
  261. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
  262. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
  263. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
  264. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
  265. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
  266. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_typed_cli.py +0 -0
  267. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_typed_mapping_get.py +0 -0
  268. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_typed_settings_field.py +0 -0
  269. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
  270. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
  271. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
  272. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
  273. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
  274. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
  275. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/pytest_fixture_returns_closed_resource.py +0 -0
  276. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
  277. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
  278. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
  279. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/redundant_test_constructor_forwarder.py +0 -0
  280. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
  281. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
  282. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
  283. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/repeated_unimplemented_test_contract.py +0 -0
  284. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/require_constrained_api_integer.py +0 -0
  285. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/require_exp_on_jwt_decode.py +0 -0
  286. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
  287. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
  288. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
  289. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/require_injectable_retry_sleep.py +0 -0
  290. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
  291. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
  292. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
  293. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/require_precise_factory_signature.py +0 -0
  294. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
  295. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
  296. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/require_pydantic_for_mapping_shape.py +0 -0
  297. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
  298. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
  299. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
  300. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
  301. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/stepdown.py +0 -0
  302. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/store_field_update_reuses_upsert.py +0 -0
  303. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
  304. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
  305. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
  306. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/test_without_explicit_oracle.py +0 -0
  307. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
  308. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
  309. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
  310. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
  311. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
  312. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/rules/unused_test_factory_option.py +0 -0
  313. {sarj_python_lint-1.95.0 → sarj_python_lint-1.97.0}/src/sarj_python_lint/suppression_policy.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sarj-python-lint
3
- Version: 1.95.0
3
+ Version: 1.97.0
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.95.0"
3
+ version = "1.97.0"
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" }]
@@ -701,9 +701,13 @@ def _stub(statement: ast.stmt) -> bool:
701
701
 
702
702
 
703
703
  def builtin_object(node: ast.expr, facts: MappingShapeFacts, at: ast.AST) -> bool:
704
- candidate = facts.qualified(node, at) == "builtins.object" or (
704
+ return builtin_symbol(node, "object", facts, at)
705
+
706
+
707
+ def builtin_symbol(node: ast.expr, name: str, facts: MappingShapeFacts, at: ast.AST) -> bool:
708
+ candidate = facts.qualified(node, at) == f"builtins.{name}" or (
705
709
  isinstance(node, ast.Name)
706
- and node.id == "object"
710
+ and node.id == name
707
711
  and not facts.shadowed(node.id, at)
708
712
  and facts.provenance.binding(node.id, at) is None
709
713
  )
@@ -717,13 +721,11 @@ def builtin_object(node: ast.expr, facts: MappingShapeFacts, at: ast.AST) -> boo
717
721
  while isinstance(root, ast.Attribute):
718
722
  root = root.value
719
723
  if isinstance(root, ast.Name):
720
- changed = native.namespace_replaced(root.id) if root.id == "object" else native.namespace_rebound(root.id)
724
+ changed = native.namespace_replaced(root.id) if root.id == name else native.namespace_rebound(root.id)
721
725
  if changed:
722
726
  return False
723
727
  attribute_mutation = any(
724
- isinstance(member.ctx, ast.Store | ast.Del)
725
- and member.attr == "object"
726
- and _builtins_module(member.value, context)
728
+ isinstance(member.ctx, ast.Store | ast.Del) and member.attr == name and _builtins_module(member.value, context)
727
729
  for member in context.nodes(ast.Attribute)
728
730
  )
729
731
  return not attribute_mutation and not any(
@@ -731,7 +733,7 @@ def builtin_object(node: ast.expr, facts: MappingShapeFacts, at: ast.AST) -> boo
731
733
  and call.func.id in {"setattr", "delattr"}
732
734
  and len(call.args) >= _PAIR_ARITY
733
735
  and _builtins_module(call.args[0], context)
734
- and (not isinstance(call.args[1], ast.Constant) or call.args[1].value == "object")
736
+ and (not isinstance(call.args[1], ast.Constant) or call.args[1].value == name)
735
737
  for call in context.nodes(ast.Call)
736
738
  )
737
739
 
@@ -12,6 +12,7 @@ from pathlib import Path
12
12
  import re
13
13
  from types import MappingProxyType
14
14
  from typing import TYPE_CHECKING, final
15
+ from weakref import WeakMethod
15
16
 
16
17
  from sarj_rule_contracts import SourceSnapshot
17
18
 
@@ -25,7 +26,7 @@ from sarj_python_lint.rules._paths import is_generated
25
26
 
26
27
 
27
28
  if TYPE_CHECKING:
28
- from collections.abc import Iterator, Sequence, Set as AbstractSet
29
+ from collections.abc import Callable, Iterator, Sequence, Set as AbstractSet
29
30
  from typing import Self
30
31
 
31
32
  from sarj_python_lint._prepared_sources import PreparedSourceInputs
@@ -191,6 +192,13 @@ class _TypeProviderFacts:
191
192
  opaque: bool
192
193
 
193
194
 
195
+ @dataclass(frozen=True)
196
+ class _ImportNamespaceWrites:
197
+ modules: frozenset[str]
198
+ dependencies: frozenset[str]
199
+ incomplete: bool
200
+
201
+
194
202
  def imports_outside(tree: ast.Module | None, modules: frozenset[str]) -> bool:
195
203
  if tree is None:
196
204
  return True
@@ -202,6 +210,48 @@ def imports_outside(tree: ast.Module | None, modules: frozenset[str]) -> bool:
202
210
  return False
203
211
 
204
212
 
213
+ @final
214
+ class ImportNamespaceMutations:
215
+ def __init__(
216
+ self,
217
+ load: Callable[[], Callable[[], Mapping[str, _ImportNamespaceWrites]] | None],
218
+ ) -> None:
219
+ self._load = load
220
+ self._facts: Mapping[str, _ImportNamespaceWrites] | None = None
221
+ self._reachable: dict[str, frozenset[str] | None] = {}
222
+
223
+ def for_unit(self, unit: SourceUnit) -> frozenset[str] | None:
224
+ if unit.module is None:
225
+ return frozenset()
226
+ if unit.module in self._reachable:
227
+ return self._reachable[unit.module]
228
+ pending = list(_module_prefixes(unit.module))
229
+ visited: set[str] = set()
230
+ mutated: set[str] = set()
231
+ if self._facts is None:
232
+ load = self._load()
233
+ if load is None:
234
+ return None
235
+ self._facts = load()
236
+ facts = self._facts
237
+ while pending:
238
+ module = pending.pop()
239
+ if module in visited:
240
+ continue
241
+ visited.add(module)
242
+ fact = facts.get(module)
243
+ if fact is None:
244
+ continue
245
+ if fact.incomplete:
246
+ self._reachable[unit.module] = None
247
+ return None
248
+ mutated.update(fact.modules)
249
+ pending.extend(fact.dependencies - visited)
250
+ result = frozenset(mutated)
251
+ self._reachable[unit.module] = result
252
+ return result
253
+
254
+
205
255
  @final
206
256
  class ProjectIndexSet:
207
257
  # Borrowed ASTs and import mappings must stay unchanged for this index's lifetime.
@@ -225,6 +275,7 @@ class ProjectIndexSet:
225
275
  self._type_providers: dict[ast.Module, _TypeProviderFacts] = {}
226
276
  self._bound_value_prefixes: dict[str, bool] = {}
227
277
  self._value_origins_incomplete = False
278
+ self.import_namespace_mutations = ImportNamespaceMutations(WeakMethod(self._namespace_write_inventory))
228
279
  by_module = {unit.module: unit for unit in units.values() if unit.module is not None}
229
280
  self._by_module = MappingProxyType(by_module)
230
281
  classes: dict[SymbolRef, ClassSummary] = {}
@@ -380,6 +431,13 @@ class ProjectIndexSet:
380
431
  def source_unit(self, module: str) -> SourceUnit | None:
381
432
  return self._by_module.get(module)
382
433
 
434
+ def _namespace_write_inventory(self) -> Mapping[str, _ImportNamespaceWrites]:
435
+ def resolve(origin: SymbolRef) -> tuple[SymbolRef, ...] | None:
436
+ values = self._canonical_value_symbols(origin)
437
+ return None if not values and self._value_origins_incomplete else values
438
+
439
+ return _import_namespace_write_facts(self._units, self._runtime_origins, resolve)
440
+
383
441
  def nominal_membership_is_dynamic(self, symbol: SymbolRef) -> bool:
384
442
  if symbol.module not in self._namespace_mutation:
385
443
  unit = self.source_unit(symbol.module)
@@ -767,6 +825,79 @@ def _namespace_closure(
767
825
  return MappingProxyType({name: frozenset(targets) for name, targets in values.items()})
768
826
 
769
827
 
828
+ def _import_namespace_write_facts(
829
+ units: Mapping[Path, SourceUnit],
830
+ runtime_origins: Mapping[str, Mapping[str, frozenset[SymbolRef]]],
831
+ resolve: Callable[[SymbolRef], tuple[SymbolRef, ...] | None],
832
+ ) -> Mapping[str, _ImportNamespaceWrites]:
833
+ facts: dict[str, _ImportNamespaceWrites] = {}
834
+ for unit in units.values():
835
+ if unit.module is None or unit.tree is None:
836
+ continue
837
+ current = _unit_import_namespace_writes(unit, runtime_origins.get(unit.module, {}), resolve)
838
+ previous = facts.get(unit.module)
839
+ if previous is not None:
840
+ current = _ImportNamespaceWrites(
841
+ previous.modules | current.modules,
842
+ previous.dependencies | current.dependencies,
843
+ previous.incomplete or current.incomplete,
844
+ )
845
+ facts[unit.module] = current
846
+ return MappingProxyType(facts)
847
+
848
+
849
+ def _unit_import_namespace_writes(
850
+ unit: SourceUnit,
851
+ origins: Mapping[str, frozenset[SymbolRef]],
852
+ resolve: Callable[[SymbolRef], tuple[SymbolRef, ...] | None],
853
+ ) -> _ImportNamespaceWrites:
854
+ targets: set[str] = set()
855
+ incomplete = False
856
+ if unit.tree is not None:
857
+ for node in walk_ast(unit.tree):
858
+ reference = _namespace_write_owner(node)
859
+ if reference is None:
860
+ continue
861
+ for origin in _possible_class_symbols(unit, reference, origins):
862
+ resolved = resolve(origin)
863
+ if resolved is None:
864
+ incomplete = True
865
+ else:
866
+ targets.update(symbol.module or symbol.name for symbol in resolved)
867
+ return _ImportNamespaceWrites(frozenset(targets), _runtime_dependency_modules(unit), incomplete)
868
+
869
+
870
+ def _namespace_write_owner(node: ast.AST) -> ast.Name | ast.Attribute | None:
871
+ owner: ast.expr | None = None
872
+ match node:
873
+ case ast.Attribute(value=value, ctx=ast.Store() | ast.Del()):
874
+ owner = value
875
+ case ast.Call(func=ast.Name(id="setattr" | "delattr"), args=[value, _, *_]):
876
+ owner = value
877
+ case _:
878
+ pass
879
+ return owner if isinstance(owner, ast.Name | ast.Attribute) else None
880
+
881
+
882
+ def _runtime_dependency_modules(unit: SourceUnit) -> frozenset[str]:
883
+ if unit.tree is None:
884
+ return frozenset()
885
+ package = (unit.module or "") if unit.path.name == "__init__.py" else (unit.module or "").rpartition(".")[0]
886
+ dependencies: set[str] = set()
887
+ for statement in _runtime_import_statements(unit.tree):
888
+ match statement:
889
+ case ast.Import(names=aliases):
890
+ for alias in aliases:
891
+ dependencies.update(_module_prefixes(alias.name))
892
+ case ast.ImportFrom(module=module, level=level, names=aliases):
893
+ target = _relative_module(package, level, module)
894
+ if target is None:
895
+ continue
896
+ dependencies.update(_module_prefixes(target))
897
+ dependencies.update(f"{target}.{alias.name}" for alias in aliases if alias.name != "*")
898
+ return frozenset(dependencies)
899
+
900
+
770
901
  def _runtime_import_origins(
771
902
  unit: SourceUnit, *, node_index: NodeIndex | None = None
772
903
  ) -> dict[str, frozenset[SymbolRef]]:
@@ -196,7 +196,8 @@ def _visible_constructors(
196
196
  scope_chain: list[int] = []
197
197
  current = owner
198
198
  while True:
199
- scope_chain.append(id(current))
199
+ if current is owner or not isinstance(current, ast.ClassDef):
200
+ scope_chain.append(id(current))
200
201
  parent = parents.get(current)
201
202
  if parent is None:
202
203
  break
@@ -498,7 +499,7 @@ def _parse_signal(sql: str) -> str | None:
498
499
  for statement in parse_postgres(normalized):
499
500
  if statement is not None and (signal := _architecture_signal(statement)) is not None:
500
501
  return signal
501
- except SqlglotError:
502
+ except SqlglotError, RecursionError:
502
503
  return None
503
504
  return None
504
505
 
@@ -554,8 +555,17 @@ def _self_join(select: exp.Select, joins: tuple[exp.Join, ...]) -> bool:
554
555
  from sqlglot import exp # ruff: ignore[import-outside-top-level] -- compare only literal relation identities.
555
556
 
556
557
  from_clause = _expression_arg(select, "from_")
557
- root = relation_key(_expression_arg(from_clause, "this")) if isinstance(from_clause, exp.From) else None
558
- return root is not None and any(relation_key(_expression_arg(join, "this")) == root for join in joins)
558
+ relations = [_expression_arg(from_clause, "this")] if isinstance(from_clause, exp.From) else []
559
+ relations.extend(_expression_arg(join, "this") for join in joins)
560
+ seen: set[tuple[str, ...]] = set()
561
+ for relation in relations:
562
+ key = relation_key(relation)
563
+ if key is None or any(_SQL_HOLE in name for name in key):
564
+ continue
565
+ if key in seen:
566
+ return True
567
+ seen.add(key)
568
+ return False
559
569
 
560
570
 
561
571
  def _derived_architecture_signal(statement: exp.Expr) -> str | None:
@@ -647,7 +657,9 @@ def _record_sql_module_imports(node: ast.Import, owner_id: int, constructors: se
647
657
 
648
658
  def _query_review_guidance(text_value: str) -> str:
649
659
  coordination = re.search(
650
- r"\b(?:FOR\s+(?:NO\s+KEY\s+)?UPDATE|FOR\s+SHARE|SKIP\s+LOCKED)\b", text_value, re.IGNORECASE
660
+ r"\b(?:FOR\s+(?:(?:NO\s+KEY\s+)?UPDATE|(?:KEY\s+)?SHARE)|SKIP\s+LOCKED)\b",
661
+ strip_sql_noise(text_value),
662
+ re.IGNORECASE,
651
663
  )
652
664
  return (
653
665
  " preserve the atomic statement; review bounds, ordering, and locks, then document its cardinality, "
@@ -61,7 +61,7 @@ class NoCustomControlFlowException(Rule):
61
61
  autofix=AutofixPolicy.NONE,
62
62
  limitations=(
63
63
  "This review warning checks stable module-level local Exception/ValueError subclasses whose bodies contain only pass, ellipsis or docstring expressions, including empty local subclasses of those markers. A source-visible direct raise of the class or its constructor is required; imported errors, payload-bearing classes, methods, decorators, generic/ambiguous bases and unused definitions abstain.",
64
- "Raising a ValueError-derived marker from an import-proven Pydantic field/model validator or legacy validator preserves that rejection protocol. Unknown external bases and visible escapes of the class to registrations, callbacks or other value consumers abstain; HTTPException and other framework-required exception types remain valid.",
64
+ "Raising a ValueError-derived marker from an import-proven Pydantic field/model validator or legacy validator preserves that rejection protocol. Unknown external bases and visible mutations or escapes of the class or a local base to registrations, callbacks or other value consumers abstain; HTTPException and other framework-required exception types remain valid.",
65
65
  "Expectedness is not inferred from a name, message or prefix. Genuine exceptional markers may also match and require review rather than conversion. Cross-module callers and registrations, indirect raises, dynamically mutated namespaces and class aliases are not inferred.",
66
66
  "Tests, generated and vendor code are excluded. No automatic rewrite is safe: a result return must preserve failure handling and transaction/resource unwinding. SARJ435 separately reviews joined-string reason identities.",
67
67
  ),
@@ -114,11 +114,10 @@ class NoCustomControlFlowException(Rule):
114
114
  if provenance.wildcard or provenance.dynamic_namespace or not provenance.builtin_namespace_untouched:
115
115
  return []
116
116
  markers = _markers(context, provenance)
117
+ raised_markers = _direct_raises(markers, context, provenance)
117
118
  findings: list[Diagnostic] = []
118
119
  for marker in markers.values():
119
- if marker.name in provenance.mutated or _escapes(marker, context, provenance):
120
- continue
121
- if not _direct_raises(marker, context, provenance):
120
+ if marker not in raised_markers:
122
121
  continue
123
122
  if is_suppressed(context.source_lines, marker.lineno, self.code):
124
123
  continue
@@ -152,8 +151,13 @@ def _markers(context: PythonFileContext, provenance: ResourceProvenance) -> dict
152
151
  and provenance.binding(base.id, base) is markers.get(base.id)
153
152
  and base.id in markers
154
153
  )
155
- if local or _builtin_base(base, context, provenance):
156
- markers[node.name] = node
154
+ if not (local or _builtin_base(base, context, provenance)):
155
+ continue
156
+ if node.name in provenance.mutated or node.name in provenance.external_bindings:
157
+ continue
158
+ if _escapes(node, context, provenance):
159
+ continue
160
+ markers[node.name] = node
157
161
  return markers
158
162
 
159
163
 
@@ -181,14 +185,24 @@ def _builtin_base(base: ast.expr, context: PythonFileContext, provenance: Resour
181
185
  return any(provenance.imported(base, f"builtins.{name}") for name in _BUILTIN_BASES)
182
186
 
183
187
 
184
- def _direct_raises(marker: ast.ClassDef, context: PythonFileContext, provenance: ResourceProvenance) -> bool:
188
+ def _direct_raises(
189
+ markers: dict[str, ast.ClassDef], context: PythonFileContext, provenance: ResourceProvenance
190
+ ) -> set[ast.ClassDef]:
191
+ candidates = set(markers.values())
192
+ raised_markers: set[ast.ClassDef] = set()
193
+ value_errors: dict[ast.ClassDef, bool] = {}
185
194
  for raised in context.nodes(ast.Raise):
186
195
  target = raised.exc.func if isinstance(raised.exc, ast.Call) else raised.exc
187
- if not isinstance(target, ast.Name) or provenance.binding(target.id, target) is not marker:
196
+ if not isinstance(target, ast.Name):
188
197
  continue
189
- if not (_value_error_marker(marker, context, provenance) and _validation_callback(raised, context, provenance)):
190
- return True
191
- return False
198
+ marker = provenance.binding(target.id, target)
199
+ if not isinstance(marker, ast.ClassDef) or marker not in candidates or marker in raised_markers:
200
+ continue
201
+ if marker not in value_errors:
202
+ value_errors[marker] = _value_error_marker(marker, context, provenance)
203
+ if not (value_errors[marker] and _validation_callback(raised, context, provenance)):
204
+ raised_markers.add(marker)
205
+ return raised_markers
192
206
 
193
207
 
194
208
  def _value_error_marker(marker: ast.ClassDef, context: PythonFileContext, provenance: ResourceProvenance) -> bool:
@@ -80,7 +80,7 @@ class NoDiscardedTaggedOutcome(ProjectRule):
80
80
  autofix=AutofixPolicy.NONE,
81
81
  limitations=(
82
82
  "Review warning for standalone synchronous calls and directly awaited async calls to stable source-visible module functions. The return must resolve to at least two direct Pydantic, dataclass or required TypedDict variants sharing a string Literal discriminator with disjoint values. No name such as Result or Error establishes proof.",
83
- "Module-local and prepared-project absolute imports, quoted bare aliases and PEP 604 returns, unquoted typing.Union and Annotated, and bounded non-generic type aliases are supported. Quoted typing-wrapper combinations, unknown receivers, decorated or generic functions, re-exports, optional/scalar branches, generic records, inheritance, dynamic namespaces, rebound identities and unsupported annotations abstain.",
83
+ "Module-local and prepared-project absolute imports, quoted bare aliases and PEP 604 returns, unquoted typing.Union and Annotated, and bounded non-generic type aliases are supported. Quoted typing-wrapper combinations, unknown receivers, decorated or generic functions, re-exports, optional/scalar branches, generic records, inheritance, dynamic namespaces, rebound or escaped callable identities, generator functions and unsupported annotations abstain.",
84
84
  "Named assignments, returned, passed or conditionally consumed results are preserved. A direct assignment to the single underscore target is an explicit discard and is reviewed. An unawaited async call belongs to coroutine checks. Direct class-body execution, generated sources and opaque providers are excluded. This rule identifies discarding; it does not prove that an assignment handles every variant or infer expected failure from a record name.",
85
85
  "String Literal tags must be direct instance fields on every variant and retain their original class-scope binding. Quoted field tags remain outside the proof; quoted module return annotations retain their source declaration anchor. Dynamic fields, optional TypedDict fields, non-string tags, computed Literal values and multi-field discriminator hierarchies are not inferred. No automatic rewrite changes call behavior or error handling.",
86
86
  ),
@@ -145,6 +145,7 @@ class _OutcomeCalls:
145
145
  self.contracts = DeclaredContracts(context)
146
146
  self.providers: dict[Path, PythonFileContext] = {context.path: context}
147
147
  self.outcomes: dict[_Function, bool] = {}
148
+ self.generator_owners: dict[Path, set[ast.AST | None]] = {}
148
149
 
149
150
  def discarded(self, statement: _Discard) -> bool:
150
151
  value = statement.value
@@ -162,11 +163,21 @@ class _OutcomeCalls:
162
163
  members = (
163
164
  self._members(_Reference(source.context, function.returns, function), frozenset())
164
165
  if function.returns is not None
166
+ and _callable_identity(source.context, function)
167
+ and self._non_generator(source)
165
168
  else None
166
169
  )
167
170
  self.outcomes[function] = members is not None and self._tagged(members)
168
171
  return self.outcomes[function]
169
172
 
173
+ def _non_generator(self, source: _FunctionSource) -> bool:
174
+ owner = source.context
175
+ if owner.path not in self.generator_owners:
176
+ self.generator_owners[owner.path] = {
177
+ owner.static_resource_provenance.scope(node) for node in owner.nodes(ast.Yield, ast.YieldFrom)
178
+ }
179
+ return source.function not in self.generator_owners[owner.path]
180
+
170
181
  def _function_source(self, expression: ast.expr) -> _FunctionSource | None:
171
182
  provenance = self.context.static_resource_provenance
172
183
  if provenance.dynamic_namespace or provenance.wildcard:
@@ -325,6 +336,44 @@ class _OutcomeCalls:
325
336
  return _record_tags(declaration, provider)
326
337
 
327
338
 
339
+ def _callable_identity(context: PythonFileContext, function: _Function) -> bool:
340
+ provenance = context.static_resource_provenance
341
+ pending: list[_Function | ast.Name] = [function]
342
+ seen: set[ast.AST] = set()
343
+ while pending:
344
+ binding = pending.pop()
345
+ if binding in seen:
346
+ continue
347
+ if len(seen) >= _MAX_DEPTH:
348
+ return False
349
+ seen.add(binding)
350
+ name = binding.id if isinstance(binding, ast.Name) else binding.name
351
+ if name in provenance.mutated or name in provenance.external_bindings:
352
+ return False
353
+ for read in provenance.binding_reads(name, binding):
354
+ parent = context.parents.get(read)
355
+ if isinstance(parent, ast.Call) and parent.func is read:
356
+ continue
357
+ target = _simple_callable_alias(context, read)
358
+ if target is None:
359
+ return False
360
+ pending.append(target)
361
+ return True
362
+
363
+
364
+ def _simple_callable_alias(context: PythonFileContext, read: ast.Name) -> ast.Name | None:
365
+ assignment = context.parents.get(read)
366
+ if not isinstance(assignment, ast.Assign | ast.AnnAssign) or assignment.value is not read:
367
+ return None
368
+ if not isinstance(context.parents.get(assignment), ast.Module | ast.FunctionDef | ast.AsyncFunctionDef):
369
+ return None
370
+ targets = assignment.targets if isinstance(assignment, ast.Assign) else [assignment.target]
371
+ if len(targets) != 1 or not isinstance(targets[0], ast.Name):
372
+ return None
373
+ target = targets[0]
374
+ return target if context.static_resource_provenance.binding(target.id, target) is target else None
375
+
376
+
328
377
  def _union_children(node: ast.expr, context: PythonFileContext) -> list[ast.expr] | None:
329
378
  if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
330
379
  return [node.left, node.right]