sarj-python-lint 1.101.0__tar.gz → 1.101.10__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 (315) hide show
  1. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/PKG-INFO +1 -1
  2. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/pyproject.toml +1 -1
  3. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_opaque_contracts.py +12 -5
  4. sarj_python_lint-1.101.10/src/sarj_python_lint/rules/_postgres_ctas.py +191 -0
  5. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_transactional_sql.py +16 -6
  6. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +39 -3
  7. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_precise_object_contract.py +5 -2
  8. sarj_python_lint-1.101.10/src/sarj_python_lint/rules/prefer_typed_mapping_get.py +378 -0
  9. sarj_python_lint-1.101.0/src/sarj_python_lint/rules/prefer_typed_mapping_get.py +0 -189
  10. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/.gitignore +0 -0
  11. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/LICENSE +0 -0
  12. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/README.md +0 -0
  13. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/__init__.py +0 -0
  14. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/__main__.py +0 -0
  15. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_analysis_session.py +0 -0
  16. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix.py +0 -0
  17. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_aliases.py +0 -0
  18. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_annotations.py +0 -0
  19. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_comments.py +0 -0
  20. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_declared_contracts.py +0 -0
  21. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_declared_tests.py +0 -0
  22. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_docs.py +0 -0
  23. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_enums.py +0 -0
  24. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_exhaustiveness.py +0 -0
  25. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_inert.py +0 -0
  26. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_parameters.py +0 -0
  27. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_repeated.py +0 -0
  28. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_security.py +0 -0
  29. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_sql_projection.py +0 -0
  30. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_tests.py +0 -0
  31. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_file_context.py +0 -0
  32. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_filesystem.py +0 -0
  33. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_fixes.py +0 -0
  34. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_parallel.py +0 -0
  35. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_prepared_sources.py +0 -0
  36. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_python_target.py +0 -0
  37. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_ratchet_cli.py +0 -0
  38. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_rule_descriptors.py +0 -0
  39. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_secret_names.py +0 -0
  40. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_source.py +0 -0
  41. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_version.py +0 -0
  42. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/application_logging.py +0 -0
  43. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/autofix.py +0 -0
  44. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/benchmark.py +0 -0
  45. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/cast_access.py +0 -0
  46. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/interpreter_argv.py +0 -0
  47. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/json_boundary.py +0 -0
  48. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/py.typed +0 -0
  49. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/ratchet.py +0 -0
  50. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rule_base.py +0 -0
  51. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rule_metadata.py +0 -0
  52. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/__init__.py +0 -0
  53. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_annotation_origins.py +0 -0
  54. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
  55. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_ast_index.py +0 -0
  56. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_ast_names.py +0 -0
  57. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_ast_position.py +0 -0
  58. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_async_lifecycle.py +0 -0
  59. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_binding_inventory.py +0 -0
  60. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_closed_helpers.py +0 -0
  61. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_comment_narration.py +0 -0
  62. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_comments.py +0 -0
  63. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
  64. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_copy_on_write.py +0 -0
  65. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_data_union_discriminator.py +0 -0
  66. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_declared_contracts.py +0 -0
  67. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
  68. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_docstrings.py +0 -0
  69. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_exports.py +0 -0
  70. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_fastapi.py +0 -0
  71. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_first_party.py +0 -0
  72. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
  73. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_imports.py +0 -0
  74. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_inert_model_annotation.py +0 -0
  75. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_inherited_contract.py +0 -0
  76. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_local_alias_fix.py +0 -0
  77. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_local_source.py +0 -0
  78. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_logging.py +0 -0
  79. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_mapping_shape_callbacks.py +0 -0
  80. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_namespace_access.py +0 -0
  81. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_native_namespace_capability.py +0 -0
  82. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_native_object_contracts.py +0 -0
  83. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
  84. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_numeric_proof.py +0 -0
  85. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_paths.py +0 -0
  86. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_postgres.py +0 -0
  87. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_project_index.py +0 -0
  88. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
  89. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_pydantic_field_contract.py +0 -0
  90. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_pytest.py +0 -0
  91. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_registry.py +0 -0
  92. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_resolved_operation_signature.py +0 -0
  93. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
  94. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_route_shapes.py +0 -0
  95. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_runtime_bindings.py +0 -0
  96. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_runtime_registry.py +0 -0
  97. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_service_http_callbacks.py +0 -0
  98. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_set_fields.py +0 -0
  99. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_sql.py +0 -0
  100. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_sql_aggregate_identity.py +0 -0
  101. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_sql_explain.py +0 -0
  102. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_sql_policy_source.py +0 -0
  103. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_static_json_alias.py +0 -0
  104. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_store_sql.py +0 -0
  105. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_store_writes.py +0 -0
  106. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
  107. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
  108. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_test_composition.py +0 -0
  109. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_test_provenance.py +0 -0
  110. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_type_guard_symbols.py +0 -0
  111. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
  112. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/async_executor_shutdown.py +0 -0
  113. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
  114. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/async_subprocess_cancellation_cleanup.py +0 -0
  115. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/cancel_owned_task_without_join.py +0 -0
  116. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
  117. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
  118. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/delete_route_returns_no_content.py +0 -0
  119. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
  120. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
  121. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/duplicate_adjacent_exception_handler.py +0 -0
  122. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/duplicate_closed_pure_helper.py +0 -0
  123. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/duplicate_pytest_fixture_params.py +0 -0
  124. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
  125. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/failed_probe_zero_threshold.py +0 -0
  126. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
  127. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
  128. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
  129. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
  130. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
  131. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
  132. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
  133. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/nan_hidden_by_builtin_min.py +0 -0
  134. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
  135. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
  136. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_async_client_in_constructor.py +0 -0
  137. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_async_function_cache.py +0 -0
  138. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_before_validator_input_mutation.py +0 -0
  139. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_blanket_suppression.py +0 -0
  140. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_broad_keyword_capture.py +0 -0
  141. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
  142. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_conflicting_pydantic_alias_validation.py +0 -0
  143. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
  144. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_contradictory_type_guard.py +0 -0
  145. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
  146. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
  147. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_create_verb_in_post_path.py +0 -0
  148. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_custom_control_flow_exception.py +0 -0
  149. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
  150. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_defaulted_environment_setting.py +0 -0
  151. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
  152. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_discarded_tagged_outcome.py +0 -0
  153. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_discarded_validation_result.py +0 -0
  154. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_dual_shape_model_field_reader.py +0 -0
  155. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
  156. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
  157. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_duplicate_field_validator_body.py +0 -0
  158. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_exception_text_in_500_detail.py +0 -0
  159. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
  160. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
  161. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
  162. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
  163. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
  164. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_fixed_sleep_in_loop.py +0 -0
  165. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_folded_bad_request_not_found.py +0 -0
  166. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
  167. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_generic_json_parser.py +0 -0
  168. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
  169. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_hasattr.py +0 -0
  170. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
  171. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_impossible_pydantic_field_bounds.py +0 -0
  172. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
  173. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_input_model_mutation.py +0 -0
  174. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_interpreter_source_arguments.py +0 -0
  175. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
  176. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_invalid_pydantic_bypass.py +0 -0
  177. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_invalid_pydantic_validator_return.py +0 -0
  178. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_loguru_exc_info.py +0 -0
  179. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_loguru_printf_format.py +0 -0
  180. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_mocked_pydantic_value_object.py +0 -0
  181. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_mutating_container_transform.py +0 -0
  182. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_mutating_input_with_result.py +0 -0
  183. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
  184. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
  185. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
  186. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_partial_type_is.py +0 -0
  187. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
  188. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
  189. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
  190. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
  191. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
  192. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_recording_store.py +0 -0
  193. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_redundant_attribute_unpacking.py +0 -0
  194. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
  195. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_redundant_local_alias.py +0 -0
  196. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
  197. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_redundant_sql_alias.py +0 -0
  198. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
  199. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
  200. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
  201. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
  202. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_select_star.py +0 -0
  203. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
  204. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
  205. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_shallow_record_type_guard.py +0 -0
  206. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_slash_collection_root_under_prefix.py +0 -0
  207. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
  208. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
  209. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
  210. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_test_comments.py +0 -0
  211. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_test_method_grafting.py +0 -0
  212. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
  213. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
  214. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_unknown_pydantic_validator_field.py +0 -0
  215. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
  216. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_unused_copy_result.py +0 -0
  217. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +0 -0
  218. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
  219. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
  220. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
  221. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_work_verb_get_route.py +0 -0
  222. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
  223. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
  224. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
  225. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_application_model_joins.py +0 -0
  226. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +0 -0
  227. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_bulk_upsert.py +0 -0
  228. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
  229. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
  230. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
  231. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_declarative_batch_validation.py +0 -0
  232. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_direct_import_module.py +0 -0
  233. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_discriminated_model_union.py +0 -0
  234. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
  235. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_grouped_settings.py +0 -0
  236. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
  237. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
  238. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
  239. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
  240. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
  241. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
  242. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
  243. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
  244. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
  245. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
  246. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
  247. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_native_string_check.py +0 -0
  248. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
  249. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
  250. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_optional_composite.py +0 -0
  251. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
  252. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_psycopg_executemany.py +0 -0
  253. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
  254. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_pydantic_model_assertion.py +0 -0
  255. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_pytest_dependency_fixtures.py +0 -0
  256. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_pytest_fixture_contract.py +0 -0
  257. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +0 -0
  258. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
  259. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_required_constructor_parameters.py +0 -0
  260. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_runtime_validation.py +0 -0
  261. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
  262. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
  263. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
  264. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
  265. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
  266. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_typed_cli.py +0 -0
  267. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_typed_settings_field.py +0 -0
  268. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
  269. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
  270. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
  271. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
  272. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
  273. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
  274. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/pytest_fixture_returns_closed_resource.py +0 -0
  275. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
  276. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
  277. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
  278. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/redundant_test_constructor_forwarder.py +0 -0
  279. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
  280. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
  281. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
  282. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/repeated_unimplemented_test_contract.py +0 -0
  283. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_constrained_api_integer.py +0 -0
  284. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_exp_on_jwt_decode.py +0 -0
  285. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
  286. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
  287. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
  288. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_injectable_retry_sleep.py +0 -0
  289. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
  290. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
  291. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
  292. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_precise_factory_signature.py +0 -0
  293. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
  294. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
  295. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_pydantic_for_mapping_shape.py +0 -0
  296. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
  297. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
  298. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
  299. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/service_singleton_delegates_to_bulk.py +0 -0
  300. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
  301. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/stepdown.py +0 -0
  302. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/store_field_update_reuses_upsert.py +0 -0
  303. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
  304. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/store_insert_requires_explicit_conflict_policy.py +0 -0
  305. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
  306. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/store_mutation_command_fanout.py +0 -0
  307. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
  308. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/test_without_explicit_oracle.py +0 -0
  309. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
  310. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
  311. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
  312. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
  313. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
  314. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/unused_test_factory_option.py +0 -0
  315. {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/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.101.0
3
+ Version: 1.101.10
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.101.0"
3
+ version = "1.101.10"
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" }]
@@ -16,6 +16,7 @@ if TYPE_CHECKING:
16
16
  from pathlib import Path
17
17
 
18
18
  from sarj_python_lint._file_context import PythonFileContext
19
+ from sarj_python_lint.rules._local_source import LocalSourceFacts
19
20
 
20
21
 
21
22
  type _Function = ast.FunctionDef | ast.AsyncFunctionDef
@@ -111,11 +112,13 @@ class OpaqueContractFacts:
111
112
  context: PythonFileContext,
112
113
  facts: MappingShapeFacts,
113
114
  *,
115
+ local_source: LocalSourceFacts,
114
116
  modules: dict[Path, OpaqueContractFacts] | None = None,
115
117
  budget: _ProofBudget | None = None,
116
118
  ) -> None:
117
119
  self.context = context
118
120
  self.facts = facts
121
+ self.local_source = local_source
119
122
  self.native = NativeObjectContracts(context, facts)
120
123
  self.guards: dict[str, _Refinement | None] = {}
121
124
  self.checked: dict[_Function, frozenset[ast.arg]] = {}
@@ -712,20 +715,24 @@ class OpaqueContractFacts:
712
715
 
713
716
  def _imported_source(self, qualified: str) -> tuple[OpaqueContractFacts, ast.FunctionDef] | None:
714
717
  module, _, name = qualified.rpartition(".")
715
- path = self.context.session.local_source.resolve_module(
716
- self.context.path, module, 0, facts=self.context.session.first_party
717
- )
718
+ path = self.local_source.resolve_module(self.context.path, module, 0, facts=self.context.session.first_party)
718
719
  if path is not None and (owner := self.modules.get(path.resolve())) is not None:
719
720
  return owner.export(name)
720
721
  if len(self.modules) >= _MAX_GUARDS:
721
722
  return None
722
- loaded = self.context.session.local_source.read_module(path) if path is not None else None
723
+ loaded = self.local_source.read_module(path) if path is not None else None
723
724
  if loaded is None:
724
725
  return None
725
726
  from sarj_python_lint._file_context import PythonFileContext # ruff: ignore[import-outside-top-level] -- source loading runs after AnalysisSession initialization.
726
727
 
727
728
  context = PythonFileContext(loaded.path, loaded.source, self.context.session)
728
- owner = OpaqueContractFacts(context, MappingShapeFacts(context), modules=self.modules, budget=self.budget)
729
+ owner = OpaqueContractFacts(
730
+ context,
731
+ MappingShapeFacts(context),
732
+ local_source=self.local_source,
733
+ modules=self.modules,
734
+ budget=self.budget,
735
+ )
729
736
  return owner.export(name)
730
737
 
731
738
  def export(self, name: str) -> tuple[OpaqueContractFacts, ast.FunctionDef] | None:
@@ -0,0 +1,191 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from typing import TYPE_CHECKING
5
+
6
+ import sqlglot
7
+ from sqlglot import exp
8
+ from sqlglot.errors import SqlglotError
9
+ from sqlglot.tokenizer_core import TokenType
10
+
11
+
12
+ if TYPE_CHECKING:
13
+ from collections.abc import Sequence
14
+
15
+ from sqlglot.tokenizer_core import Token
16
+
17
+
18
+ _COPY_END = re.compile(r"(?m)^\\\.(?:\r?$)")
19
+ _TEMP_TABLE = (TokenType.CREATE, TokenType.TEMPORARY, TokenType.TABLE)
20
+ _ON_COMMIT_DROP = (TokenType.ON, TokenType.COMMIT, TokenType.DROP)
21
+ _ON_COMMIT_ROWS_SIZE = 4
22
+
23
+
24
+ def normalize_postgres_ctas(source: str) -> str:
25
+ source = _mask_copy_input(source)
26
+ try:
27
+ tokens = sqlglot.tokenize(source, read="postgres")
28
+ except SqlglotError, RecursionError:
29
+ return source
30
+ output = list(source)
31
+ statement: list[Token] = []
32
+ for token in tokens:
33
+ if token.token_type is not TokenType.SEMICOLON:
34
+ statement.append(token)
35
+ continue
36
+ _normalize_header(output, statement)
37
+ statement = []
38
+ _normalize_header(output, statement)
39
+ return "".join(output)
40
+
41
+
42
+ def _mask_copy_input(source: str) -> str:
43
+ if "COPY" not in source.upper():
44
+ return source
45
+ output = list(source)
46
+ start = 0
47
+ for separator in re.finditer(r";", source):
48
+ if separator.start() < start:
49
+ continue
50
+ try:
51
+ tokens = sqlglot.tokenize(source[start : separator.end()], read="postgres")
52
+ except SqlglotError, RecursionError:
53
+ continue
54
+ if not tokens or tokens[-1].token_type is not TokenType.SEMICOLON:
55
+ continue
56
+ if start + tokens[-1].end != separator.start():
57
+ continue
58
+ if _copy_from_stdin(tokens):
59
+ marker = _COPY_END.search(source, separator.end())
60
+ end = marker.end() if marker is not None else len(source)
61
+ _blank(output, start, end)
62
+ start = end
63
+ else:
64
+ start = separator.end()
65
+ return "".join(output)
66
+
67
+
68
+ def _normalize_header(output: list[str], tokens: Sequence[Token]) -> None:
69
+ if not _is_table_create(tokens):
70
+ return
71
+ depth = 0
72
+ for index, token in enumerate(tokens):
73
+ if token.token_type is TokenType.L_PAREN:
74
+ depth += 1
75
+ elif token.token_type is TokenType.R_PAREN:
76
+ depth -= 1
77
+ elif depth == 0 and token.token_type is TokenType.ALIAS:
78
+ spans = _ignored_header_spans(tokens[:index])
79
+ if not spans:
80
+ return
81
+ start = tokens[0].start
82
+ candidate = output[start : tokens[-1].end + 1]
83
+ for first, last in spans:
84
+ _blank(candidate, first.start - start, last.end + 1 - start)
85
+ if _is_query_create("".join(candidate)):
86
+ for first, last in spans:
87
+ _blank(output, first.start, last.end + 1)
88
+ return
89
+
90
+
91
+ def _temporary_qualifier(tokens: Sequence[Token]) -> Token | None:
92
+ if len(tokens) > 1 and tokens[1].token_type is TokenType.VAR and tokens[1].text.upper() in {"GLOBAL", "LOCAL"}:
93
+ return tokens[1]
94
+ return None
95
+
96
+
97
+ def _is_table_create(tokens: Sequence[Token]) -> bool:
98
+ kinds = tuple(token.token_type for token in tokens[:4])
99
+ if kinds[:2] == (TokenType.CREATE, TokenType.TABLE) or kinds[:3] == _TEMP_TABLE:
100
+ return True
101
+ if kinds[:3] == (TokenType.CREATE, TokenType.VAR, TokenType.TABLE):
102
+ return tokens[1].text.upper() == "UNLOGGED"
103
+ return (
104
+ kinds == (TokenType.CREATE, TokenType.VAR, TokenType.TEMPORARY, TokenType.TABLE)
105
+ and _temporary_qualifier(tokens) is not None
106
+ )
107
+
108
+
109
+ def _ignored_header_spans(tokens: Sequence[Token]) -> tuple[tuple[Token, Token], ...]:
110
+ spans: list[tuple[Token, Token]] = []
111
+ qualifier = _temporary_qualifier(tokens)
112
+ if qualifier is not None:
113
+ spans.append((qualifier, qualifier))
114
+ end = len(tokens)
115
+ if _has_tablespace_property(tokens):
116
+ spans.append((tokens[-2], tokens[-1]))
117
+ end -= 2
118
+ commit_start = _commit_property_start(tokens, end)
119
+ if commit_start < end and tokens[end - 1].token_type is TokenType.DROP:
120
+ spans.append((tokens[commit_start], tokens[end - 1]))
121
+ if _has_without_oids_property(tokens[:commit_start]):
122
+ spans.append((tokens[commit_start - 2], tokens[commit_start - 1]))
123
+ return tuple(spans)
124
+
125
+
126
+ def _commit_property_start(tokens: Sequence[Token], end: int) -> int:
127
+ if tuple(token.token_type for token in tokens[end - 3 : end]) == _ON_COMMIT_DROP:
128
+ return end - 3
129
+ if end < _ON_COMMIT_ROWS_SIZE or tuple(
130
+ token.token_type for token in tokens[end - _ON_COMMIT_ROWS_SIZE : end - 2]
131
+ ) != (TokenType.ON, TokenType.COMMIT):
132
+ return end
133
+ action, rows = tokens[end - 2 : end]
134
+ if rows.token_type is TokenType.ROWS and (
135
+ action.token_type is TokenType.DELETE
136
+ or (action.token_type is TokenType.VAR and action.text.upper() == "PRESERVE")
137
+ ):
138
+ return end - _ON_COMMIT_ROWS_SIZE
139
+ return end
140
+
141
+
142
+ def _has_without_oids_property(tokens: Sequence[Token]) -> bool:
143
+ return (
144
+ len(tokens) > 1
145
+ and tokens[-2].token_type is TokenType.VAR
146
+ and tokens[-1].token_type is TokenType.VAR
147
+ and tokens[-2].text.upper() == "WITHOUT"
148
+ and tokens[-1].text.upper() == "OIDS"
149
+ )
150
+
151
+
152
+ def _has_tablespace_property(tokens: Sequence[Token]) -> bool:
153
+ return (
154
+ len(tokens) > 1
155
+ and tokens[-2].token_type is TokenType.VAR
156
+ and tokens[-2].text.upper() == "TABLESPACE"
157
+ and tokens[-1].token_type in {TokenType.VAR, TokenType.IDENTIFIER}
158
+ )
159
+
160
+
161
+ def _is_query_create(candidate: str) -> bool:
162
+ try:
163
+ parsed = sqlglot.parse_one(candidate, read="postgres")
164
+ except SqlglotError, RecursionError:
165
+ return False
166
+ return (
167
+ isinstance(parsed, exp.Create)
168
+ and parsed.args.get("kind") == "TABLE"
169
+ and isinstance(parsed.args.get("expression"), exp.Query)
170
+ )
171
+
172
+
173
+ def _copy_from_stdin(tokens: Sequence[Token]) -> bool:
174
+ if not tokens or tokens[0].token_type is not TokenType.COPY:
175
+ return False
176
+ depth = 0
177
+ for index, token in enumerate(tokens[:-1]):
178
+ if token.token_type is TokenType.L_PAREN:
179
+ depth += 1
180
+ elif token.token_type is TokenType.R_PAREN:
181
+ depth -= 1
182
+ elif depth == 0 and token.token_type is TokenType.FROM:
183
+ following = tokens[index + 1]
184
+ return following.token_type is TokenType.VAR and following.text.upper() == "STDIN"
185
+ return False
186
+
187
+
188
+ def _blank(output: list[str], start: int, end: int) -> None:
189
+ for index in range(start, end):
190
+ if output[index] not in {"\r", "\n"}:
191
+ output[index] = " "
@@ -87,6 +87,7 @@ _NATIVE_CONNECTIONS = frozenset(
87
87
  )
88
88
  _SELECT = re.compile(r"\bSELECT\b", re.IGNORECASE)
89
89
  _PLACEHOLDER = re.compile(r"%(?:\([^)]+\))?s")
90
+ _POSTGRES_PLACEHOLDER = re.compile(r"%%|%(?:\([^)]+\))?[sbt]")
90
91
  _FORMAT_HOLE = re.compile(r"(?<!\{)\{(?:[A-Za-z_]\w*|\d*)\}(?!\})")
91
92
  _SQL_HOLE = "__sarj_sql_hole__"
92
93
  _MAX_WRAPPER_DEPTH = 8
@@ -127,11 +128,19 @@ def query_signal(sql: str, *, dialect: str = "postgres") -> str | None:
127
128
 
128
129
 
129
130
  def _prepared_sql(sql: str, dialect: str) -> str:
130
- prepared = _FORMAT_HOLE.sub(_SQL_HOLE, _PLACEHOLDER.sub("?", sql))
131
- if dialect == "postgres" and "EXPLAIN" in prepared.upper():
132
- from sarj_python_lint.rules._sql_explain import normalize_postgres_explain # ruff: ignore[import-outside-top-level] -- only executing EXPLAIN needs native token normalization.
131
+ parameters = _POSTGRES_PLACEHOLDER if dialect == "postgres" else _PLACEHOLDER
132
+ prepared = _FORMAT_HOLE.sub(
133
+ _SQL_HOLE,
134
+ parameters.sub(lambda match: ("%" if match.group() == "%%" else "?").ljust(len(match.group())), sql),
135
+ )
136
+ if dialect == "postgres":
137
+ from sarj_python_lint.rules._postgres_ctas import normalize_postgres_ctas # ruff: ignore[import-outside-top-level] -- recover PostgreSQL temporary-table queries only after the SELECT gate.
138
+
139
+ prepared = normalize_postgres_ctas(prepared)
140
+ if "EXPLAIN" in prepared.upper():
141
+ from sarj_python_lint.rules._sql_explain import normalize_postgres_explain # ruff: ignore[import-outside-top-level] -- only executing EXPLAIN needs native token normalization.
133
142
 
134
- prepared = normalize_postgres_explain(prepared)
143
+ prepared = normalize_postgres_ctas(normalize_postgres_explain(prepared))
135
144
  if "GROUP" in prepared.upper() and ("/*" in prepared or "--" in prepared):
136
145
  import sqlglot # ruff: ignore[import-outside-top-level] -- tokenize only GROUP candidates with comments.
137
146
 
@@ -173,13 +182,14 @@ def _statement_signal(statement: exp.Expr, sql: str, dialect: str) -> str | None
173
182
 
174
183
 
175
184
  def transactional_queries(context: PythonFileContext) -> Iterator[TransactionalQuery]:
176
- if _SELECT.search(context.source) is None:
185
+ queries = tuple(_recover_queries(context))
186
+ if not queries:
177
187
  return
178
188
  dialects = _source_dialects(context)
179
189
  if not dialects or dialects == {"analytical"}:
180
190
  return
181
191
  single = next(iter(dialects)) if len(dialects) == 1 else None
182
- for candidate in _recover_queries(context):
192
+ for candidate in queries:
183
193
  dialect = single or _executing_dialect(candidate.node, context)
184
194
  if dialect is not None and dialect != "analytical":
185
195
  yield TransactionalQuery(candidate.node, candidate.sql, dialect)
@@ -34,7 +34,7 @@ _COMMON_AGGREGATE = re.compile(
34
34
  re.IGNORECASE,
35
35
  )
36
36
  _LOCKING_READ = re.compile(r"\b(?:FOR\s+(?:NO\s+KEY\s+)?UPDATE|FOR\s+SHARE|SKIP\s+LOCKED)\b", re.IGNORECASE)
37
- _PLACEHOLDER = re.compile(r"%(?:\([^)]+\))?s")
37
+ _PLACEHOLDER = re.compile(r"%%|%(?:\([^)]+\))?[sbt]")
38
38
  _GROUP_KEYS_LIMIT = 2
39
39
  _GROUP_AGGREGATES_LIMIT = 2
40
40
  _SINGLE_GROUP_AGGREGATES_LIMIT = 3
@@ -68,7 +68,9 @@ def _grouped_reporting_signal(sql: str) -> str | None:
68
68
  if _GROUP_BY.search(sql) is None or _COMMON_AGGREGATE.search(sql) is None:
69
69
  return None
70
70
  try:
71
- statements = parse_postgres(_PLACEHOLDER.sub("?", sql))
71
+ statements = parse_postgres(
72
+ _PLACEHOLDER.sub(lambda match: ("%" if match.group() == "%%" else "?").ljust(len(match.group())), sql)
73
+ )
72
74
  except SqlglotError, RecursionError:
73
75
  return None
74
76
  for statement in statements:
@@ -141,7 +143,7 @@ class NoAnalyticalAggregationInPostgresStore(Rule):
141
143
  aliases=("no-aggregation-in-store-query", "no-analytical-queries-in-transactional-db"),
142
144
  limitations=(
143
145
  "Statically recoverable SQL in non-test, non-generated Python modules with native PostgreSQL, MySQL, or SQLite imports is analyzed, regardless of filename. The historical SARJ020 identifier is retained.",
144
- "Every parsed SELECT DISTINCT (including DISTINCT ON), deduplicating UNION/INTERSECT/EXCEPT, GROUP BY, and built-in SQL aggregate is reported, including CTEs, nested writes, windowed aggregates, identity-bounded queries, and LIMIT queries. ALL set operations remain valid. This deliberately replaces the former reporting-size thresholds.",
146
+ "Every parsed SELECT DISTINCT (including DISTINCT ON), deduplicating UNION/INTERSECT/EXCEPT, GROUP BY, and built-in SQL aggregate is reported, including temporary-table AS queries, CTEs, nested writes, windowed aggregates, identity-bounded queries, and LIMIT queries. ALL set operations remain valid. This deliberately replaces the former reporting-size thresholds.",
145
147
  "A single imported backend owns module SQL. Resolvable first-party query contracts and re-exports retain their native analytical-provider evidence. Mixed backend modules require a direct query sink on a source-proven native connection or annotated parameter; unresolved receivers and separately bound queries abstain.",
146
148
  "Known ClickHouse, BigQuery, DuckDB, Snowflake, Trino, Athena, and Databricks drivers are analytical owners. Comments, scalar SQL values, identifiers, Python docstrings, and IS DISTINCT FROM do not trigger the policy.",
147
149
  "SQLite multi-argument MIN/MAX and MySQL ANY_VALUE retain their scalar semantics; PostgreSQL ANY_VALUE remains an aggregate.",
@@ -165,6 +167,40 @@ class NoAnalyticalAggregationInPostgresStore(Rule):
165
167
  expected_count=1,
166
168
  public=True,
167
169
  ),
170
+ RuleExample(
171
+ example_id="temporary-table-distinct",
172
+ scenario="temporary-table",
173
+ title="A temporary PostgreSQL table still performs deduplication",
174
+ outcome=ExampleOutcome.MATCH,
175
+ files=(
176
+ ExampleFile.python(
177
+ "app/event_store.py",
178
+ "import psycopg\n\n"
179
+ 'QUERY = "CREATE TEMP TABLE report ON COMMIT DROP AS WITH rows AS '
180
+ '(SELECT DISTINCT team_id FROM event) SELECT team_id FROM rows"\n',
181
+ ),
182
+ ),
183
+ focus_path=PurePosixPath("app/event_store.py"),
184
+ expected_count=1,
185
+ public=True,
186
+ ),
187
+ RuleExample(
188
+ example_id="temporary-table-operational-read",
189
+ scenario="temporary-table",
190
+ title="A temporary PostgreSQL table can materialize an operational row lookup",
191
+ outcome=ExampleOutcome.NO_MATCH,
192
+ files=(
193
+ ExampleFile.python(
194
+ "app/event_store.py",
195
+ "import psycopg\n\n"
196
+ 'QUERY = "CREATE TEMP TABLE report ON COMMIT DROP AS WITH rows AS '
197
+ '(SELECT team_id FROM event WHERE id = %s) SELECT team_id FROM rows"\n',
198
+ ),
199
+ ),
200
+ focus_path=PurePosixPath("app/event_store.py"),
201
+ expected_count=0,
202
+ public=True,
203
+ ),
168
204
  RuleExample(
169
205
  example_id="operational-existence-lookup",
170
206
  title="PostgreSQL performs an operational existence lookup",
@@ -15,6 +15,7 @@ from sarj_python_lint.rule_base import (
15
15
  RuleExample,
16
16
  Severity,
17
17
  )
18
+ from sarj_python_lint.rules._local_source import LocalSourceFacts
18
19
  from sarj_python_lint.rules._native_object_contracts import builtin_object, builtin_symbol
19
20
  from sarj_python_lint.rules._opaque_contracts import REFINEMENT_TYPES, OpaqueContractFacts
20
21
  from sarj_python_lint.rules.require_pydantic_for_mapping_shape import MappingShapeFacts
@@ -48,7 +49,7 @@ class PreferPreciseObjectContract(Rule):
48
49
  "Safe fixes narrow only a bare builtin object return annotation to builtin str for a closed private nested synchronous helper returning one exact string literal, with every call used directly as an if test and all containing return contracts explicit. Existing inert/metadata/binding proofs must hold; public/domain/container/parameter/model contracts and other result uses remain review-only.",
49
50
  "Checks builtin object in function signatures and class field annotations, including supported containers, callables, optional unions and quoted annotations. Local opaque values, object() sentinels, Literal/Annotated metadata, framework hooks, proven override signatures, and registered raw Pydantic callbacks are excluded. Functions that directly validate an object parameter through a source-visible BaseModel, BaseSettings or RootModel model_validate call, positionally or with obj=, retain that raw boundary. JSON text inputs still require a text or byte contract. Aliases must resolve to their source declaration and their bodies use definition scope. Alias graphs are bounded and shared branches reuse their facts. Imported or shadowed application types named object are preserved. Genuine opaque public contracts can use an explained exact-code exception; narrowing outside the exact private truthiness-only subset remains manual.",
50
51
  "An import-proven TypeGuard or TypeIs retains bare object on its guarded positional parameter and unchecked object slots in its declared refinement result; other object parameters remain checked. Guard correctness belongs to the type-guard rules. Universal type[object] class contracts and the return of a canonical module-level PEP 562 __getattr__ hook retain their opaque runtime contracts.",
51
- "Ordinary raw validators retain object inputs tied to builtin isinstance, exact builtin type comparisons or an actual source-resolved TypeGuard/TypeIs through rejecting branches, actual type/refinement assertions, accepting terminal branches with a rejecting fallback, or conditional expressions. Stable projections from containers with unchecked value slots retain their raw root contract when those values are validated. Source-visible local and imported validators may delegate those inputs and raw results; precise result narrowing does not justify a bare object output. Related unchecked mapping projections and transforms retain unknown values; import-proven native parsers and JSONDecoder preserve raw outputs. Universal builtin and stdlib interoperation may retain raw inputs. Independent object parameters, domain constructors and unproven parser names remain checked. Source resolution and dataflow are bounded with cycle guards; rebinding, decorators and namespace mutation invalidate delegated proof.",
52
+ "Ordinary raw validators retain object inputs tied to builtin isinstance, exact builtin type comparisons or an actual source-resolved TypeGuard/TypeIs through rejecting branches, actual type/refinement assertions, accepting terminal branches with a rejecting fallback, or conditional expressions. Stable projections from containers with unchecked value slots retain their raw root contract when those values are validated. Source-visible local and imported validators may delegate those inputs and raw results; precise result narrowing does not justify a bare object output. Related unchecked mapping projections and transforms retain unknown values; import-proven native parsers and JSONDecoder preserve raw outputs. Universal builtin and stdlib interoperation may retain raw inputs. Independent object parameters, domain constructors and unproven parser names remain checked. Source resolution and dataflow use a bounded per-file proof cache, captured source inputs and cycle guards; rebinding, decorators and namespace mutation invalidate delegated proof.",
52
53
  "Native opaque contracts include canonical ast.Constant.value reads and captures, FunctionType invocations, identity-only inputs and sys.getrefcount. Actual exec/eval globals and locals retain unknown values only through bounded native dict construction and alias flow; unrelated dictionaries and source domain factories do not borrow that ownership. Stub property returns on an import-proven runtime_checkable Protocol retain unchecked incoming attributes. Generic callable results, ordinary Protocol methods, application properties and unused parameters remain checked.",
53
54
  "Raw input unions may include scalar or None branches; only genuine unchecked container branches seed raw projections. Mapping consumers that inspect only keys retain uninspected value slots. Projected aliases require simple statement dominance, and precise active guards permit typed consumption after validation. Native namespace output reads require a preceding direct function-scope execution and abstain after authored mutations. Benign builtins imports do not hide builtin object contracts; explicit object shadowing and source-visible object mutations remain outside scope.",
54
55
  "An import-proven Iterable of unchecked values retains its raw element contract when every input use is a direct synchronous iteration and every reachable element read directly enters source-proven Pydantic model_validate. Deferred closures, rebinding, other iterator/element uses, unknown model providers and JSON-text parsers do not establish that boundary.",
@@ -131,7 +132,9 @@ class PreferPreciseObjectContract(Rule):
131
132
  if facts.provenance.wildcard:
132
133
  return []
133
134
  findings: list[Diagnostic] = []
134
- opaque = OpaqueContractFacts(context, facts)
135
+ opaque = OpaqueContractFacts(
136
+ context, facts, local_source=LocalSourceFacts(source_inputs=context.session.source_inputs)
137
+ )
135
138
  for owner, annotation in _contracts(context):
136
139
  if not _has_object(annotation, context, facts, at=annotation):
137
140
  continue