sarj-python-lint 1.37.0__tar.gz → 1.38.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 (204) hide show
  1. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/PKG-INFO +1 -1
  2. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/pyproject.toml +1 -1
  3. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_registry.py +2 -0
  4. sarj_python_lint-1.38.0/src/sarj_python_lint/rules/no_async_function_cache.py +179 -0
  5. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/.gitignore +0 -0
  6. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/LICENSE +0 -0
  7. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/README.md +0 -0
  8. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/__init__.py +0 -0
  9. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/__main__.py +0 -0
  10. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/_analysis_session.py +0 -0
  11. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/_file_context.py +0 -0
  12. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/_filesystem.py +0 -0
  13. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/_python_target.py +0 -0
  14. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/_ratchet_cli.py +0 -0
  15. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/_secret_names.py +0 -0
  16. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/_source.py +0 -0
  17. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/_version.py +0 -0
  18. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/benchmark.py +0 -0
  19. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/interpreter_argv.py +0 -0
  20. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/json_boundary.py +0 -0
  21. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/py.typed +0 -0
  22. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/ratchet.py +0 -0
  23. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rule_base.py +0 -0
  24. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/__init__.py +0 -0
  25. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
  26. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_ast_index.py +0 -0
  27. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_ast_position.py +0 -0
  28. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_closed_helpers.py +0 -0
  29. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_comments.py +0 -0
  30. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
  31. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_copy_on_write.py +0 -0
  32. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
  33. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_docstrings.py +0 -0
  34. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_exports.py +0 -0
  35. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_fastapi.py +0 -0
  36. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_first_party.py +0 -0
  37. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
  38. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_imports.py +0 -0
  39. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_inert_model_annotation.py +0 -0
  40. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_local_source.py +0 -0
  41. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_logging.py +0 -0
  42. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_namespace_access.py +0 -0
  43. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
  44. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_paths.py +0 -0
  45. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_project_index.py +0 -0
  46. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
  47. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_pydantic_field_contract.py +0 -0
  48. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_pytest.py +0 -0
  49. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_resolved_operation_signature.py +0 -0
  50. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
  51. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_set_fields.py +0 -0
  52. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_sql.py +0 -0
  53. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_static_json_alias.py +0 -0
  54. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
  55. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
  56. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_test_composition.py +0 -0
  57. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/_test_provenance.py +0 -0
  58. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
  59. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
  60. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
  61. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
  62. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
  63. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
  64. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/duplicate_adjacent_exception_handler.py +0 -0
  65. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/duplicate_closed_pure_helper.py +0 -0
  66. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
  67. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
  68. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
  69. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
  70. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
  71. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
  72. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
  73. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
  74. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
  75. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
  76. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
  77. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_before_validator_input_mutation.py +0 -0
  78. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_broad_keyword_capture.py +0 -0
  79. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
  80. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_conflicting_pydantic_alias_validation.py +0 -0
  81. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
  82. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
  83. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
  84. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
  85. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
  86. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
  87. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
  88. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
  89. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
  90. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
  91. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
  92. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
  93. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_fixed_sleep_in_loop.py +0 -0
  94. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
  95. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
  96. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
  97. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_impossible_pydantic_field_bounds.py +0 -0
  98. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
  99. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_input_model_mutation.py +0 -0
  100. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_interpreter_source_arguments.py +0 -0
  101. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
  102. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_mocked_pydantic_value_object.py +0 -0
  103. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
  104. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
  105. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
  106. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
  107. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
  108. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
  109. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
  110. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
  111. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
  112. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
  113. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
  114. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
  115. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
  116. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
  117. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_select_star.py +0 -0
  118. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
  119. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
  120. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
  121. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
  122. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
  123. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_test_method_grafting.py +0 -0
  124. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
  125. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
  126. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_unknown_pydantic_validator_field.py +0 -0
  127. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
  128. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_unused_copy_result.py +0 -0
  129. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +0 -0
  130. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
  131. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
  132. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
  133. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
  134. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
  135. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
  136. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +0 -0
  137. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
  138. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
  139. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
  140. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_declarative_batch_validation.py +0 -0
  141. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
  142. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
  143. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
  144. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
  145. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
  146. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
  147. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
  148. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
  149. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
  150. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
  151. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
  152. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
  153. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_native_string_check.py +0 -0
  154. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
  155. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
  156. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
  157. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
  158. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +0 -0
  159. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
  160. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_required_constructor_parameters.py +0 -0
  161. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
  162. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
  163. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
  164. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
  165. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
  166. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
  167. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
  168. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
  169. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
  170. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
  171. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
  172. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
  173. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
  174. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
  175. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/redundant_test_constructor_forwarder.py +0 -0
  176. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
  177. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
  178. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
  179. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/repeated_unimplemented_test_contract.py +0 -0
  180. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
  181. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
  182. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
  183. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/require_injectable_retry_sleep.py +0 -0
  184. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
  185. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
  186. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
  187. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/require_precise_factory_signature.py +0 -0
  188. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
  189. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
  190. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
  191. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
  192. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
  193. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
  194. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/stepdown.py +0 -0
  195. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
  196. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
  197. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
  198. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/test_without_explicit_oracle.py +0 -0
  199. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
  200. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
  201. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
  202. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
  203. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
  204. {sarj_python_lint-1.37.0 → sarj_python_lint-1.38.0}/src/sarj_python_lint/rules/unused_test_factory_option.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sarj-python-lint
3
- Version: 1.37.0
3
+ Version: 1.38.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.37.0"
3
+ version = "1.38.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" }]
@@ -32,6 +32,7 @@ from sarj_python_lint.rules.no_analytical_aggregation_in_postgres_store import (
32
32
  NoAnalyticalAggregationInPostgresStore,
33
33
  )
34
34
  from sarj_python_lint.rules.no_any_mapping_types import NoAnyMappingTypes
35
+ from sarj_python_lint.rules.no_async_function_cache import NoAsyncFunctionCache
35
36
  from sarj_python_lint.rules.no_before_validator_input_mutation import NoBeforeValidatorInputMutation
36
37
  from sarj_python_lint.rules.no_broad_keyword_capture import NoBroadKeywordCapture
37
38
  from sarj_python_lint.rules.no_comment_cruft import NoCommentCruft
@@ -241,6 +242,7 @@ REGISTRY: Mapping[str, type[Rule]] = MappingProxyType(
241
242
  NoSwallowedAsyncioCancellation.id: NoSwallowedAsyncioCancellation,
242
243
  RequireExplicitPsycopgTransaction.id: RequireExplicitPsycopgTransaction,
243
244
  AsyncMockCallWithoutAwaitAssertion.id: AsyncMockCallWithoutAwaitAssertion,
245
+ NoAsyncFunctionCache.id: NoAsyncFunctionCache,
244
246
  ComplexPostgresQueryRequiresArchitectureReview.id: ComplexPostgresQueryRequiresArchitectureReview,
245
247
  ExcessiveCommentary.id: ExcessiveCommentary,
246
248
  PreferWalrusAwaitedNoneGuard.id: PreferWalrusAwaitedNoneGuard,
@@ -0,0 +1,179 @@
1
+ from __future__ import annotations
2
+
3
+ import ast
4
+ from pathlib import PurePosixPath
5
+ from typing import TYPE_CHECKING, ClassVar, 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 children
20
+
21
+
22
+ if TYPE_CHECKING:
23
+ from sarj_python_lint._file_context import PythonFileContext
24
+ from sarj_python_lint.rules._imports import ImportIndex
25
+
26
+
27
+ _FUNCTOOLS = frozenset({"functools"})
28
+ _COROUTINE_CACHES = frozenset({"cache", "cached_property", "lru_cache"})
29
+ _LRU_CACHE_POSITIONAL_ARGUMENTS = 2
30
+
31
+
32
+ @final
33
+ class NoAsyncFunctionCache(Rule):
34
+ id = "no-async-function-cache"
35
+ code = "SARJ507"
36
+ documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
37
+ default_level=Severity.WARNING,
38
+ summary="Standard library cache decorates a coroutine function and retains single-use coroutine objects.",
39
+ rationale=(
40
+ "`functools.cache`, `lru_cache`, and `cached_property` store the coroutine object returned by an async "
41
+ "function rather than its awaited value. A subsequent cache hit can raise `RuntimeError: cannot reuse "
42
+ "already awaited coroutine`."
43
+ ),
44
+ remediation="Remove the standard library cache or use an async-aware cache that stores completed results.",
45
+ category=RuleCategory.CORRECTNESS,
46
+ autofix=AutofixPolicy.NONE,
47
+ limitations=(
48
+ "Only a proven functools import used as the innermost decorator on a coroutine function is reported.",
49
+ "Async generators, transformed functions, ambiguous or rebound imports, and generated files are excluded.",
50
+ "Wildcard imports and names rebound by relative imports or imports outside the module body are excluded conservatively.",
51
+ "lru_cache with disabled, dynamic, or unpacked maxsize arguments is excluded; an omitted size or literal positive integer or None is required.",
52
+ "Indirect wrapping calls and runtime monkeypatches are not resolved. Test code is checked because coroutine reuse fails there too.",
53
+ "No automatic rewrite is offered because cache lifetime, cancellation, and concurrency require an explicit design decision.",
54
+ ),
55
+ examples=(
56
+ RuleExample(
57
+ example_id="cached-coroutine-function",
58
+ title="A standard cache retains an exhausted coroutine",
59
+ outcome=ExampleOutcome.MATCH,
60
+ files=(
61
+ ExampleFile.python(
62
+ "app/cache.py",
63
+ "from functools import cache\n\n@cache\nasync def load() -> int:\n return 1\n",
64
+ ),
65
+ ),
66
+ focus_path=PurePosixPath("app/cache.py"),
67
+ expected_count=1,
68
+ public=True,
69
+ ),
70
+ RuleExample(
71
+ example_id="fresh-coroutine-function",
72
+ title="Each call creates a fresh coroutine",
73
+ outcome=ExampleOutcome.NO_MATCH,
74
+ files=(ExampleFile.python("app/cache.py", "async def load() -> int:\n return 1\n"),),
75
+ focus_path=PurePosixPath("app/cache.py"),
76
+ expected_count=0,
77
+ public=True,
78
+ ),
79
+ ),
80
+ )
81
+ description = documentation.summary
82
+
83
+ @override
84
+ def check_context(self, context: PythonFileContext) -> list[Diagnostic]:
85
+ if "async" not in context.source or context.generated or context.tree is None:
86
+ return []
87
+ shadowed = _nested_import_names(context)
88
+ if "*" in shadowed:
89
+ return []
90
+ diagnostics: list[Diagnostic] = []
91
+ for function in context.nodes(ast.AsyncFunctionDef):
92
+ if not function.decorator_list:
93
+ continue
94
+ decorator = function.decorator_list[-1]
95
+ if (
96
+ not _is_coroutine_cache(decorator, context.imports, shadowed)
97
+ or _has_own_yield(function)
98
+ or is_suppressed(context.source_lines, decorator.lineno, self.code)
99
+ ):
100
+ continue
101
+ diagnostics.append(
102
+ Diagnostic(
103
+ path=context.path,
104
+ line=decorator.lineno,
105
+ col=decorator.col_offset + 1,
106
+ code=self.code,
107
+ message=(
108
+ "Standard library cache retains a single-use coroutine; remove it or use an async-aware "
109
+ "cache that stores awaited results."
110
+ ),
111
+ severity=Severity.WARNING,
112
+ ),
113
+ )
114
+ return diagnostics
115
+
116
+
117
+ def _nested_import_names(context: PythonFileContext) -> frozenset[str]:
118
+ return frozenset(
119
+ alias.asname or alias.name.partition(".")[0]
120
+ for node in context.nodes(ast.Import, ast.ImportFrom)
121
+ for alias in node.names
122
+ if context.parents[node] is not context.tree
123
+ or (isinstance(node, ast.ImportFrom) and node.level > 0)
124
+ or alias.name == "*"
125
+ )
126
+
127
+
128
+ def _is_coroutine_cache(decorator: ast.expr, imports: ImportIndex, shadowed: frozenset[str]) -> bool:
129
+ target = decorator.func if isinstance(decorator, ast.Call) else decorator
130
+ root = target
131
+ while isinstance(root, ast.Attribute):
132
+ root = root.value
133
+ if isinstance(root, ast.Name) and root.id in shadowed:
134
+ return False
135
+ symbol = imports.resolved_symbol(target, sources=_FUNCTOOLS)
136
+ if symbol not in _COROUTINE_CACHES:
137
+ return False
138
+ if not isinstance(decorator, ast.Call):
139
+ return True
140
+ if symbol != "lru_cache" or any(keyword.arg is None for keyword in decorator.keywords):
141
+ return False
142
+ if len(decorator.args) > _LRU_CACHE_POSITIONAL_ARGUMENTS or any(
143
+ isinstance(argument, ast.Starred) for argument in decorator.args
144
+ ):
145
+ return False
146
+ sizes = [keyword.value for keyword in decorator.keywords if keyword.arg == "maxsize"]
147
+ if decorator.args:
148
+ sizes.append(decorator.args[0])
149
+ if not sizes:
150
+ return True
151
+ if len(sizes) != 1:
152
+ return False
153
+ match sizes[0]:
154
+ case ast.Constant(value=None):
155
+ return True
156
+ case ast.Constant(value=int() as size) | ast.UnaryOp(op=ast.UAdd(), operand=ast.Constant(value=int() as size)):
157
+ return size > 0
158
+ case _:
159
+ return False
160
+
161
+
162
+ def _has_own_yield(function: ast.AsyncFunctionDef) -> bool:
163
+ pending: list[ast.AST] = list(function.body)
164
+ while pending:
165
+ match pending.pop():
166
+ case ast.Yield() | ast.YieldFrom():
167
+ return True
168
+ case ast.FunctionDef() | ast.AsyncFunctionDef() | ast.Lambda() as definition:
169
+ pending.extend(definition.args.defaults)
170
+ pending.extend(default for default in definition.args.kw_defaults if default is not None)
171
+ if not isinstance(definition, ast.Lambda):
172
+ pending.extend(definition.decorator_list)
173
+ case ast.ClassDef() as definition:
174
+ pending.extend(definition.bases)
175
+ pending.extend(keyword.value for keyword in definition.keywords)
176
+ pending.extend(definition.decorator_list)
177
+ case node:
178
+ pending.extend(children(node))
179
+ return False