sarj-python-lint 1.88.20__tar.gz → 1.90.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 (303) hide show
  1. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/PKG-INFO +1 -1
  2. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/pyproject.toml +1 -1
  3. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_ast_index.py +2 -2
  4. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_registry.py +2 -0
  5. sarj_python_lint-1.90.0/src/sarj_python_lint/rules/no_async_client_in_constructor.py +340 -0
  6. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/.gitignore +0 -0
  7. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/LICENSE +0 -0
  8. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/README.md +0 -0
  9. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/__init__.py +0 -0
  10. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/__main__.py +0 -0
  11. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_analysis_session.py +0 -0
  12. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_autofix.py +0 -0
  13. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_autofix_aliases.py +0 -0
  14. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_autofix_annotations.py +0 -0
  15. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_autofix_comments.py +0 -0
  16. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_autofix_declared_contracts.py +0 -0
  17. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_autofix_declared_tests.py +0 -0
  18. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_autofix_docs.py +0 -0
  19. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_autofix_enums.py +0 -0
  20. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_autofix_exhaustiveness.py +0 -0
  21. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_autofix_inert.py +0 -0
  22. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_autofix_parameters.py +0 -0
  23. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_autofix_repeated.py +0 -0
  24. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_autofix_security.py +0 -0
  25. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_autofix_sql_projection.py +0 -0
  26. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_autofix_tests.py +0 -0
  27. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_file_context.py +0 -0
  28. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_filesystem.py +0 -0
  29. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_fixes.py +0 -0
  30. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_parallel.py +0 -0
  31. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_prepared_sources.py +0 -0
  32. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_python_target.py +0 -0
  33. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_ratchet_cli.py +0 -0
  34. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_secret_names.py +0 -0
  35. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_source.py +0 -0
  36. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/_version.py +0 -0
  37. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/application_logging.py +0 -0
  38. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/autofix.py +0 -0
  39. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/benchmark.py +0 -0
  40. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/cast_access.py +0 -0
  41. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/interpreter_argv.py +0 -0
  42. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/json_boundary.py +0 -0
  43. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/py.typed +0 -0
  44. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/ratchet.py +0 -0
  45. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rule_base.py +0 -0
  46. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/__init__.py +0 -0
  47. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_annotation_origins.py +0 -0
  48. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
  49. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_ast_names.py +0 -0
  50. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_ast_position.py +0 -0
  51. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_async_lifecycle.py +0 -0
  52. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_binding_inventory.py +0 -0
  53. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_closed_helpers.py +0 -0
  54. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_comment_narration.py +0 -0
  55. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_comments.py +0 -0
  56. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
  57. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_copy_on_write.py +0 -0
  58. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_data_union_discriminator.py +0 -0
  59. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_declared_contracts.py +0 -0
  60. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
  61. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_docstrings.py +0 -0
  62. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_exports.py +0 -0
  63. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_fastapi.py +0 -0
  64. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_first_party.py +0 -0
  65. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
  66. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_imports.py +0 -0
  67. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_inert_model_annotation.py +0 -0
  68. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_inherited_contract.py +0 -0
  69. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_local_alias_fix.py +0 -0
  70. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_local_source.py +0 -0
  71. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_logging.py +0 -0
  72. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_mapping_shape_callbacks.py +0 -0
  73. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_namespace_access.py +0 -0
  74. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_native_namespace_capability.py +0 -0
  75. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_native_object_contracts.py +0 -0
  76. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
  77. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_numeric_proof.py +0 -0
  78. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_opaque_contracts.py +0 -0
  79. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_paths.py +0 -0
  80. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_postgres.py +0 -0
  81. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_project_index.py +0 -0
  82. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
  83. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_pydantic_field_contract.py +0 -0
  84. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_pytest.py +0 -0
  85. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_resolved_operation_signature.py +0 -0
  86. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
  87. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_route_shapes.py +0 -0
  88. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_runtime_bindings.py +0 -0
  89. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_service_http_callbacks.py +0 -0
  90. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_set_fields.py +0 -0
  91. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_sql.py +0 -0
  92. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_sql_aggregate_identity.py +0 -0
  93. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_sql_explain.py +0 -0
  94. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_sql_policy_source.py +0 -0
  95. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_static_json_alias.py +0 -0
  96. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_store_sql.py +0 -0
  97. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_store_writes.py +0 -0
  98. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
  99. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
  100. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_test_composition.py +0 -0
  101. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_test_provenance.py +0 -0
  102. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_transactional_sql.py +0 -0
  103. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/_type_guard_symbols.py +0 -0
  104. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
  105. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/async_executor_shutdown.py +0 -0
  106. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
  107. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/async_subprocess_cancellation_cleanup.py +0 -0
  108. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/cancel_owned_task_without_join.py +0 -0
  109. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
  110. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
  111. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/delete_route_returns_no_content.py +0 -0
  112. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
  113. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
  114. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/duplicate_adjacent_exception_handler.py +0 -0
  115. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/duplicate_closed_pure_helper.py +0 -0
  116. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/duplicate_pytest_fixture_params.py +0 -0
  117. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
  118. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/failed_probe_zero_threshold.py +0 -0
  119. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
  120. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
  121. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
  122. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
  123. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
  124. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
  125. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
  126. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/nan_hidden_by_builtin_min.py +0 -0
  127. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
  128. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
  129. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
  130. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_async_function_cache.py +0 -0
  131. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_before_validator_input_mutation.py +0 -0
  132. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_blanket_suppression.py +0 -0
  133. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_broad_keyword_capture.py +0 -0
  134. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
  135. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_conflicting_pydantic_alias_validation.py +0 -0
  136. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
  137. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_contradictory_type_guard.py +0 -0
  138. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
  139. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
  140. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_create_verb_in_post_path.py +0 -0
  141. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_custom_control_flow_exception.py +0 -0
  142. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
  143. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_defaulted_environment_setting.py +0 -0
  144. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
  145. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_discarded_tagged_outcome.py +0 -0
  146. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_discarded_validation_result.py +0 -0
  147. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_dual_shape_model_field_reader.py +0 -0
  148. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
  149. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
  150. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_duplicate_field_validator_body.py +0 -0
  151. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_exception_text_in_500_detail.py +0 -0
  152. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
  153. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
  154. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
  155. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
  156. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
  157. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_fixed_sleep_in_loop.py +0 -0
  158. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_folded_bad_request_not_found.py +0 -0
  159. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
  160. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
  161. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_hasattr.py +0 -0
  162. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
  163. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_impossible_pydantic_field_bounds.py +0 -0
  164. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
  165. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_input_model_mutation.py +0 -0
  166. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_interpreter_source_arguments.py +0 -0
  167. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
  168. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_invalid_pydantic_bypass.py +0 -0
  169. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_invalid_pydantic_validator_return.py +0 -0
  170. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_loguru_exc_info.py +0 -0
  171. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_loguru_printf_format.py +0 -0
  172. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_mocked_pydantic_value_object.py +0 -0
  173. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_mutating_container_transform.py +0 -0
  174. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
  175. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
  176. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
  177. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_partial_type_is.py +0 -0
  178. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
  179. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
  180. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
  181. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
  182. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
  183. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_recording_store.py +0 -0
  184. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
  185. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_redundant_local_alias.py +0 -0
  186. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
  187. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_redundant_sql_alias.py +0 -0
  188. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
  189. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
  190. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
  191. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
  192. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_select_star.py +0 -0
  193. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
  194. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
  195. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_shallow_record_type_guard.py +0 -0
  196. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_slash_collection_root_under_prefix.py +0 -0
  197. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
  198. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
  199. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
  200. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_test_method_grafting.py +0 -0
  201. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
  202. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
  203. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_unknown_pydantic_validator_field.py +0 -0
  204. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
  205. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_unused_copy_result.py +0 -0
  206. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +0 -0
  207. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
  208. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
  209. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
  210. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/no_work_verb_get_route.py +0 -0
  211. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
  212. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
  213. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
  214. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_application_model_joins.py +0 -0
  215. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +0 -0
  216. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_bulk_upsert.py +0 -0
  217. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
  218. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
  219. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
  220. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_declarative_batch_validation.py +0 -0
  221. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_direct_import_module.py +0 -0
  222. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_discriminated_model_union.py +0 -0
  223. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
  224. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_grouped_settings.py +0 -0
  225. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
  226. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
  227. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
  228. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
  229. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
  230. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
  231. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
  232. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
  233. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
  234. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
  235. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
  236. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_native_string_check.py +0 -0
  237. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
  238. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
  239. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_optional_composite.py +0 -0
  240. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
  241. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_precise_object_contract.py +0 -0
  242. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_psycopg_executemany.py +0 -0
  243. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
  244. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_pydantic_model_assertion.py +0 -0
  245. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_pytest_dependency_fixtures.py +0 -0
  246. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +0 -0
  247. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
  248. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_required_constructor_parameters.py +0 -0
  249. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_runtime_validation.py +0 -0
  250. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
  251. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
  252. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
  253. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
  254. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
  255. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_typed_cli.py +0 -0
  256. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_typed_mapping_get.py +0 -0
  257. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_typed_settings_field.py +0 -0
  258. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
  259. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
  260. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
  261. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
  262. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
  263. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
  264. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/pytest_fixture_returns_closed_resource.py +0 -0
  265. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
  266. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
  267. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
  268. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/redundant_test_constructor_forwarder.py +0 -0
  269. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
  270. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
  271. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
  272. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/repeated_unimplemented_test_contract.py +0 -0
  273. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/require_exp_on_jwt_decode.py +0 -0
  274. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
  275. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
  276. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
  277. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/require_injectable_retry_sleep.py +0 -0
  278. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
  279. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
  280. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
  281. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/require_precise_factory_signature.py +0 -0
  282. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
  283. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
  284. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/require_pydantic_for_mapping_shape.py +0 -0
  285. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
  286. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
  287. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
  288. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
  289. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/stepdown.py +0 -0
  290. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/store_field_update_reuses_upsert.py +0 -0
  291. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
  292. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/store_insert_requires_explicit_conflict_policy.py +0 -0
  293. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
  294. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/store_mutation_command_fanout.py +0 -0
  295. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
  296. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/test_without_explicit_oracle.py +0 -0
  297. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
  298. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
  299. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
  300. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
  301. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
  302. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.0}/src/sarj_python_lint/rules/unused_test_factory_option.py +0 -0
  303. {sarj_python_lint-1.88.20 → sarj_python_lint-1.90.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.88.20
3
+ Version: 1.90.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.88.20"
3
+ version = "1.90.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" }]
@@ -59,8 +59,8 @@ def comprehension_results(node: ast.ListComp | ast.SetComp | ast.DictComp | ast.
59
59
  return [child for child in children(node) if isinstance(child, ast.expr)]
60
60
 
61
61
 
62
- def has_own_yield(function: ast.AsyncFunctionDef) -> bool:
63
- pending: list[ast.AST] = list(function.body)
62
+ def has_own_yield(function: ast.FunctionDef | ast.AsyncFunctionDef | ast.Lambda) -> bool:
63
+ pending: list[ast.AST] = [function.body] if isinstance(function, ast.Lambda) else list(function.body)
64
64
  while pending:
65
65
  match pending.pop():
66
66
  case ast.Yield() | ast.YieldFrom():
@@ -225,6 +225,7 @@ from sarj_python_lint.rules.duplicate_closed_pure_helper import DuplicateClosedP
225
225
  from sarj_python_lint.rules.duplicate_pytest_fixture_params import DuplicatePytestFixtureParams
226
226
  from sarj_python_lint.rules.failed_probe_zero_threshold import FailedProbeZeroThreshold
227
227
  from sarj_python_lint.rules.nan_hidden_by_builtin_min import NanHiddenByBuiltinMin
228
+ from sarj_python_lint.rules.no_async_client_in_constructor import NoAsyncClientInConstructor
228
229
  from sarj_python_lint.rules.no_conflicting_pydantic_alias_validation import NoConflictingPydanticAliasValidation
229
230
  from sarj_python_lint.rules.no_contradictory_type_guard import NoContradictoryTypeGuard
230
231
  from sarj_python_lint.rules.no_create_verb_in_post_path import NoCreateVerbInPostPath
@@ -274,6 +275,7 @@ from sarj_python_lint.rules.test_without_explicit_oracle import NoExplicitTestOr
274
275
 
275
276
  REGISTRY: Mapping[str, type[Rule]] = MappingProxyType(
276
277
  {
278
+ NoAsyncClientInConstructor.id: NoAsyncClientInConstructor,
277
279
  NoDiscardedTaggedOutcome.id: NoDiscardedTaggedOutcome,
278
280
  StoreInsertRequiresExplicitConflictPolicy.id: StoreInsertRequiresExplicitConflictPolicy,
279
281
  StoreMutationCommandFanout.id: StoreMutationCommandFanout,
@@ -0,0 +1,340 @@
1
+ from __future__ import annotations
2
+
3
+ import ast
4
+ from pathlib import PurePosixPath
5
+ from typing import TYPE_CHECKING, final, override
6
+
7
+ from sarj_python_lint.rule_base import (
8
+ AutofixPolicy,
9
+ Diagnostic,
10
+ ExampleFile,
11
+ ExampleOutcome,
12
+ Rule,
13
+ RuleCategory,
14
+ RuleDocumentation,
15
+ RuleExample,
16
+ Severity,
17
+ is_suppressed,
18
+ )
19
+ from sarj_python_lint.rules._ast_index import has_own_yield
20
+ from sarj_python_lint.rules._resource_provenance import import_name_for_binding
21
+
22
+
23
+ if TYPE_CHECKING:
24
+ from sarj_python_lint._file_context import PythonFileContext
25
+
26
+
27
+ _CLIENTS = frozenset({"httpx.AsyncClient", "httpx._client.AsyncClient"})
28
+ _MODULES = frozenset({"httpx", "httpx._client"})
29
+ _COMPREHENSIONS = (ast.ListComp, ast.SetComp, ast.DictComp, ast.GeneratorExp)
30
+ _MAX_ALIAS_DEPTH = 32
31
+ _BAD = "import httpx\nclass Service:\n def __init__(self):\n self.client = httpx.AsyncClient()\n"
32
+ _GOOD = "from contextlib import asynccontextmanager\nimport httpx\nclass Service:\n def __init__(self, client: httpx.AsyncClient):\n self.client = client\n@asynccontextmanager\nasync def service_scope(endpoint):\n async with httpx.AsyncClient(base_url=endpoint) as client:\n yield Service(client)\n"
33
+
34
+
35
+ @final
36
+ class NoAsyncClientInConstructor(Rule):
37
+ id = "no-async-client-in-constructor"
38
+ code = "SARJ549"
39
+ documentation = RuleDocumentation(
40
+ default_level=Severity.ERROR,
41
+ summary="Inject an HTTPX AsyncClient instead of constructing one in __init__.",
42
+ rationale="Constructor-owned clients repeat transport setup for each service instance and hide the boundary that owns pooling and asynchronous cleanup.",
43
+ remediation="Create and close an appropriately scoped AsyncClient at the async composition boundary, and inject it into consumers. Keep tenant credentials, cookies, event loops and independent ownership boundaries separate; do not replace them with a global client.",
44
+ category=RuleCategory.ARCHITECTURE,
45
+ autofix=AutofixPolicy.NONE,
46
+ limitations=(
47
+ "This is an explicit architecture policy for import-proven HTTPX AsyncClient calls executed by synchronous nongenerator class __init__ methods, including import aliases and stable constructor assignment aliases bounded to 32 links, eager comprehensions and nested definition defaults/decorators.",
48
+ "One-hop same-file undecorated synchronous factories with stable lexical bindings are followed only when their sole statement after an optional docstring returns a proven constructor call. Zero-argument lambda factories are supported when invoked; deferred function/lambda/generator bodies are not constructor execution.",
49
+ "Unknown or imported factory implementations, overridable methods, wrapper chains, dynamic namespace access, wildcard imports, ambiguous/rebound aliases and visible namespace mutation are not inferred. A generator's first iterable is eager; other generator expressions remain deferred even when a caller might consume them immediately.",
50
+ "Constructor parameter defaults execute at class definition, not on each constructor call, and are outside this rule. No automatic ownership transfer, sharing decision or lifecycle rewrite is safe.",
51
+ "Annotations and lazy type-alias/type-parameter expressions are excluded: their source location does not prove constructor-time execution. Framework-driven evaluation of annotations is not inferred.",
52
+ "Escaped HTTPX module objects cause conservative abstention, including module-object assignment aliases. Constructor aliases must remain confined to calls, annotations, attribute access or stable single-name aliases; unknown argument, return or storage escapes and visible mutation invalidate the import proof.",
53
+ "Nested class bodies are followed only without bases or metaclass keywords, because custom class namespace preparation can replace imported names. Method bodies still use their normal lexical bindings. Generator factories and lambdas create deferred generators rather than clients and are excluded.",
54
+ "HTTPX recommends scoped client reuse and explicit asynchronous closure; its API does not universally prohibit constructor ownership. This stricter constructor boundary is the requested policy. See https://www.python-httpx.org/async/ . Ruff ASYNC212 instead owns blocking HTTPX use in async functions.",
55
+ ),
56
+ examples=(
57
+ RuleExample(
58
+ example_id="constructor-allocation",
59
+ title="Do not hide client allocation in a service constructor",
60
+ outcome=ExampleOutcome.MATCH,
61
+ files=(ExampleFile.python("app/service.py", _BAD),),
62
+ focus_path=PurePosixPath("app/service.py"),
63
+ expected_count=1,
64
+ public=True,
65
+ ),
66
+ RuleExample(
67
+ example_id="scoped-injection",
68
+ title="Inject a client owned by the async composition scope",
69
+ outcome=ExampleOutcome.NO_MATCH,
70
+ files=(ExampleFile.python("app/service.py", _GOOD),),
71
+ focus_path=PurePosixPath("app/service.py"),
72
+ expected_count=0,
73
+ public=True,
74
+ ),
75
+ ),
76
+ )
77
+ description = documentation.summary
78
+
79
+ @override
80
+ def check_context(self, context: PythonFileContext) -> list[Diagnostic]:
81
+ if "__init__" not in context.symbol_source or "AsyncClient" not in context.symbol_source:
82
+ return []
83
+ if context.generated or context.tree is None or context.has_wildcard_import or context.dynamic_namespace:
84
+ return []
85
+ if not _imports_untouched(context):
86
+ return []
87
+ constructors = frozenset(
88
+ node
89
+ for node in context.nodes(ast.FunctionDef)
90
+ if node.name == "__init__"
91
+ and isinstance(context.parents.get(node), ast.ClassDef)
92
+ and not has_own_yield(node)
93
+ )
94
+ factories: dict[ast.FunctionDef | ast.Lambda, bool] = {}
95
+ findings = [
96
+ Diagnostic(
97
+ path=context.path,
98
+ line=call.lineno,
99
+ col=call.col_offset + 1,
100
+ code=self.code,
101
+ severity=Severity.ERROR,
102
+ message="httpx.AsyncClient construction in __init__; inject a caller-owned, appropriately scoped AsyncClient and close it at the async composition boundary",
103
+ )
104
+ for call in context.nodes(ast.Call)
105
+ if _in_constructor(context, call, constructors)
106
+ and _allocates(context, call, follow_factory=True, factories=factories)
107
+ and not is_suppressed(context.source_lines, call.lineno, self.code)
108
+ ]
109
+ return sorted(findings, key=lambda finding: (finding.line, finding.col))
110
+
111
+
112
+ def _imports_untouched(context: PythonFileContext) -> bool:
113
+ safe: dict[ast.alias | ast.Name, bool] = {}
114
+ for binding in context.nodes(ast.alias):
115
+ expression = ast.Name(id=binding.asname or binding.name, ctx=ast.Load())
116
+ qualified = import_name_for_binding(expression, binding, context.parents.get(binding))
117
+ if (
118
+ qualified is not None
119
+ and qualified in _MODULES | _CLIENTS
120
+ and not _alias_untouched(context, binding, qualified, safe, remaining=_MAX_ALIAS_DEPTH)
121
+ ):
122
+ return False
123
+ return True
124
+
125
+
126
+ def _alias_untouched(
127
+ context: PythonFileContext,
128
+ binding: ast.alias | ast.Name,
129
+ qualified: str,
130
+ safe: dict[ast.alias | ast.Name, bool],
131
+ *,
132
+ remaining: int,
133
+ ) -> bool:
134
+ if binding in safe:
135
+ return safe[binding]
136
+ safe[binding] = False
137
+ name = binding.id if isinstance(binding, ast.Name) else binding.asname or binding.name.partition(".")[0]
138
+ if remaining == 0 or name in context.binding_inventory.mutated:
139
+ return False
140
+ safe[binding] = all(
141
+ _reference_untouched(context, read, qualified, safe, remaining=remaining)
142
+ for read in context.nodes(ast.Name)
143
+ if isinstance(read.ctx, ast.Load) and read.id == name and _binding(context, name, read) is binding
144
+ )
145
+ return safe[binding]
146
+
147
+
148
+ def _reference_untouched(
149
+ context: PythonFileContext,
150
+ expression: ast.expr,
151
+ qualified: str,
152
+ safe: dict[ast.alias | ast.Name, bool],
153
+ *,
154
+ remaining: int,
155
+ ) -> bool:
156
+ if not _runtime_expression(context, expression):
157
+ return True
158
+ while qualified in _MODULES:
159
+ parent = context.parents.get(expression)
160
+ if not isinstance(parent, ast.Attribute) or parent.value is not expression:
161
+ return False
162
+ expression, qualified = parent, f"{qualified}.{parent.attr}"
163
+ if qualified not in _CLIENTS:
164
+ return True
165
+ parent = context.parents.get(expression)
166
+ if (isinstance(parent, ast.Call) and parent.func is expression) or (
167
+ isinstance(parent, ast.Attribute) and parent.value is expression
168
+ ):
169
+ return True
170
+ target = _alias_target(context, parent, expression)
171
+ return target is not None and _alias_untouched(context, target, qualified, safe, remaining=remaining - 1)
172
+
173
+
174
+ def _alias_target(context: PythonFileContext, statement: ast.AST | None, value: ast.expr) -> ast.Name | None:
175
+ if isinstance(statement, ast.Assign) and len(statement.targets) == 1 and statement.value is value:
176
+ target = statement.targets[0]
177
+ elif isinstance(statement, ast.AnnAssign) and statement.value is value:
178
+ target = statement.target
179
+ else:
180
+ return None
181
+ if not isinstance(context.parents.get(statement), ast.Module | ast.FunctionDef | ast.AsyncFunctionDef):
182
+ return None
183
+ return target if isinstance(target, ast.Name) and _binding(context, target.id, target) is target else None
184
+
185
+
186
+ def _in_constructor(context: PythonFileContext, call: ast.Call, constructors: frozenset[ast.FunctionDef]) -> bool:
187
+ if not _runtime_expression(context, call):
188
+ return False
189
+ scope = context.binding_inventory.scope(call)
190
+ while isinstance(scope, (ast.ClassDef, *_COMPREHENSIONS)):
191
+ if isinstance(scope, ast.ClassDef) and (scope.bases or scope.keywords):
192
+ return False
193
+ if isinstance(scope, ast.GeneratorExp) and not context.resource_provenance.contains(
194
+ scope.generators[0].iter, call
195
+ ):
196
+ return False
197
+ scope = context.binding_inventory.scope(scope)
198
+ return scope in constructors
199
+
200
+
201
+ def _runtime_expression(context: PythonFileContext, expression: ast.expr) -> bool:
202
+ child: ast.AST = expression
203
+ parent = context.parents.get(child)
204
+ while parent is not None:
205
+ if isinstance(parent, ast.TypeAlias | ast.type_param):
206
+ return False
207
+ if isinstance(parent, ast.AnnAssign | ast.arg) and parent.annotation is child:
208
+ return False
209
+ if isinstance(parent, ast.FunctionDef | ast.AsyncFunctionDef) and parent.returns is child:
210
+ return False
211
+ child, parent = parent, context.parents.get(parent)
212
+ return True
213
+
214
+
215
+ def _allocates(
216
+ context: PythonFileContext,
217
+ call: ast.Call,
218
+ *,
219
+ follow_factory: bool,
220
+ factories: dict[ast.FunctionDef | ast.Lambda, bool],
221
+ ) -> bool:
222
+ target = _target(context, call.func)
223
+ if isinstance(target, str):
224
+ return target in _CLIENTS
225
+ if not follow_factory or not isinstance(target, ast.FunctionDef | ast.Lambda):
226
+ return False
227
+ if isinstance(target, ast.Lambda):
228
+ arguments = target.args
229
+ if any(
230
+ (
231
+ call.args,
232
+ call.keywords,
233
+ arguments.posonlyargs,
234
+ arguments.args,
235
+ arguments.kwonlyargs,
236
+ arguments.vararg,
237
+ arguments.kwarg,
238
+ )
239
+ ):
240
+ return False
241
+ if target not in factories:
242
+ factories[target] = _factory_allocates(context, target, factories)
243
+ return factories[target]
244
+
245
+
246
+ def _factory_allocates(
247
+ context: PythonFileContext,
248
+ target: ast.FunctionDef | ast.Lambda,
249
+ factories: dict[ast.FunctionDef | ast.Lambda, bool],
250
+ ) -> bool:
251
+ if has_own_yield(target):
252
+ return False
253
+ if isinstance(target, ast.Lambda):
254
+ return isinstance(target.body, ast.Call) and _allocates(
255
+ context, target.body, follow_factory=False, factories=factories
256
+ )
257
+ if target.decorator_list:
258
+ return False
259
+ body = target.body
260
+ if (
261
+ body
262
+ and isinstance(body[0], ast.Expr)
263
+ and isinstance(body[0].value, ast.Constant)
264
+ and isinstance(body[0].value.value, str)
265
+ ):
266
+ body = body[1:]
267
+ return (
268
+ len(body) == 1
269
+ and isinstance(body[0], ast.Return)
270
+ and isinstance(body[0].value, ast.Call)
271
+ and _allocates(context, body[0].value, follow_factory=False, factories=factories)
272
+ )
273
+
274
+
275
+ def _target(context: PythonFileContext, expression: ast.expr) -> str | ast.FunctionDef | ast.Lambda | None:
276
+ for _ in range(_MAX_ALIAS_DEPTH):
277
+ if isinstance(expression, ast.Lambda):
278
+ return expression
279
+ root = expression
280
+ while isinstance(root, ast.Attribute):
281
+ root = root.value
282
+ if not isinstance(root, ast.Name) or root.id in context.binding_inventory.mutated:
283
+ return None
284
+ binding = _binding(context, root.id, expression)
285
+ if isinstance(binding, ast.alias):
286
+ return import_name_for_binding(expression, binding, context.parents.get(binding))
287
+ if not isinstance(expression, ast.Name):
288
+ return None
289
+ if isinstance(binding, ast.FunctionDef):
290
+ return _factory_binding(context, binding, expression)
291
+ if not isinstance(binding, ast.Name):
292
+ return None
293
+ value = context.resource_provenance.assignment_value(binding, expression)
294
+ if value is None:
295
+ return None
296
+ expression = value
297
+ return None
298
+
299
+
300
+ def _factory_binding(context: PythonFileContext, definition: ast.FunctionDef, at: ast.expr) -> ast.FunctionDef | None:
301
+ parent = context.parents.get(definition)
302
+ if parent is context.tree:
303
+ return definition
304
+ if isinstance(parent, ast.FunctionDef | ast.AsyncFunctionDef) and definition.lineno < at.lineno:
305
+ return definition
306
+ return None
307
+
308
+
309
+ def _binding(context: PythonFileContext, name: str, at: ast.AST) -> ast.AST | None:
310
+ if (binding := context.resource_provenance.runtime_binding(name, at)) is not None:
311
+ return binding
312
+ scope = context.binding_inventory.scope(at)
313
+ lambda_body = False
314
+ while isinstance(scope, (*_COMPREHENSIONS, ast.Lambda)):
315
+ lambda_body |= isinstance(scope, ast.Lambda)
316
+ first_iterable = isinstance(scope, _COMPREHENSIONS) and context.resource_provenance.contains(
317
+ scope.generators[0].iter, at
318
+ )
319
+ if not first_iterable and name in context.binding_inventory.bindings.get(scope, {}):
320
+ return None
321
+ scope = context.binding_inventory.scope(scope)
322
+ bindings = context.runtime_bindings.lookup(scope, name)
323
+ if bindings is None and lambda_body:
324
+ return _lambda_module_binding(context, scope, name)
325
+ return bindings[0] if bindings is not None and len(bindings) == 1 else None
326
+
327
+
328
+ def _lambda_module_binding(context: PythonFileContext, scope: ast.AST | None, name: str) -> ast.AST | None:
329
+ if name in context.binding_inventory.external_bindings:
330
+ return None
331
+ while scope is not context.tree:
332
+ if scope is None:
333
+ return None
334
+ if isinstance(scope, ast.FunctionDef | ast.AsyncFunctionDef) and name in context.binding_inventory.bindings.get(
335
+ scope, {}
336
+ ):
337
+ return None
338
+ scope = context.binding_inventory.scope(scope)
339
+ bindings = context.runtime_bindings.lookup(scope, name)
340
+ return bindings[0] if bindings is not None and len(bindings) == 1 else None