sarj-python-lint 1.27.1__tar.gz → 1.27.3__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 (187) hide show
  1. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/PKG-INFO +1 -1
  2. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/pyproject.toml +1 -1
  3. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/interpreter_argv.py +60 -9
  4. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/require_injectable_retry_sleep.py +49 -14
  5. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/.gitignore +0 -0
  6. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/LICENSE +0 -0
  7. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/README.md +0 -0
  8. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/__init__.py +0 -0
  9. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/__main__.py +0 -0
  10. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/_analysis_session.py +0 -0
  11. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/_file_context.py +0 -0
  12. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/_filesystem.py +0 -0
  13. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/_python_target.py +0 -0
  14. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/_ratchet_cli.py +0 -0
  15. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/_secret_names.py +0 -0
  16. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/_source.py +0 -0
  17. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/_version.py +0 -0
  18. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/benchmark.py +0 -0
  19. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/json_boundary.py +0 -0
  20. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/py.typed +0 -0
  21. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/ratchet.py +0 -0
  22. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rule_base.py +0 -0
  23. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/__init__.py +0 -0
  24. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
  25. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_ast_index.py +0 -0
  26. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_ast_position.py +0 -0
  27. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_comments.py +0 -0
  28. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
  29. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_copy_on_write.py +0 -0
  30. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
  31. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_docstrings.py +0 -0
  32. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_fastapi.py +0 -0
  33. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_first_party.py +0 -0
  34. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
  35. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_imports.py +0 -0
  36. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_local_source.py +0 -0
  37. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_logging.py +0 -0
  38. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
  39. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_paths.py +0 -0
  40. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_project_index.py +0 -0
  41. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
  42. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_pytest.py +0 -0
  43. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_registry.py +0 -0
  44. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
  45. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_set_fields.py +0 -0
  46. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_sql.py +0 -0
  47. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
  48. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
  49. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_test_composition.py +0 -0
  50. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/_test_provenance.py +0 -0
  51. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
  52. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
  53. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
  54. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
  55. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
  56. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
  57. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
  58. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
  59. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
  60. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
  61. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
  62. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
  63. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
  64. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
  65. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
  66. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
  67. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
  68. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_before_validator_input_mutation.py +0 -0
  69. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_broad_keyword_capture.py +0 -0
  70. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
  71. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
  72. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
  73. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
  74. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
  75. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
  76. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
  77. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
  78. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
  79. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
  80. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
  81. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
  82. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
  83. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_fixed_sleep_in_loop.py +0 -0
  84. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
  85. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
  86. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
  87. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
  88. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_input_model_mutation.py +0 -0
  89. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_interpreter_source_arguments.py +0 -0
  90. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
  91. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_mocked_pydantic_value_object.py +0 -0
  92. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
  93. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
  94. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
  95. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
  96. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
  97. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
  98. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
  99. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
  100. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
  101. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
  102. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
  103. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
  104. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
  105. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
  106. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_select_star.py +0 -0
  107. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
  108. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
  109. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
  110. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
  111. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
  112. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_test_method_grafting.py +0 -0
  113. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
  114. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
  115. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
  116. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_unused_copy_result.py +0 -0
  117. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +0 -0
  118. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
  119. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
  120. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
  121. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
  122. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
  123. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
  124. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +0 -0
  125. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
  126. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
  127. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
  128. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
  129. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
  130. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
  131. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
  132. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
  133. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
  134. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
  135. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
  136. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
  137. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
  138. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
  139. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
  140. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_native_string_check.py +0 -0
  141. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
  142. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
  143. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
  144. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
  145. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +0 -0
  146. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
  147. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_required_constructor_parameters.py +0 -0
  148. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
  149. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
  150. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
  151. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
  152. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
  153. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
  154. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
  155. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
  156. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
  157. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
  158. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
  159. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
  160. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
  161. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
  162. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
  163. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
  164. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
  165. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
  166. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
  167. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
  168. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
  169. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
  170. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
  171. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/require_precise_factory_signature.py +0 -0
  172. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
  173. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
  174. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
  175. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
  176. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
  177. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
  178. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/stepdown.py +0 -0
  179. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
  180. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
  181. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
  182. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
  183. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
  184. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
  185. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
  186. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
  187. {sarj_python_lint-1.27.1 → sarj_python_lint-1.27.3}/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.27.1
3
+ Version: 1.27.3
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.27.1"
3
+ version = "1.27.3"
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" }]
@@ -85,18 +85,20 @@ class UnprovableCommandError(ValueError):
85
85
  """A wrapper executable position cannot be established safely."""
86
86
 
87
87
 
88
- def unwrap_command(argv: Sequence[str]) -> tuple[str, ...]:
88
+ def unwrap_command(
89
+ argv: Sequence[str], *, allow_shell_builtins: bool = True, allowed_wrappers: frozenset[str] | None = None
90
+ ) -> tuple[str, ...]:
89
91
  current = tuple(argv)
90
92
  for _ in range(_MAX_WRAPPERS):
91
93
  if not current:
92
94
  return ()
93
95
  command = PurePosixPath(current[0]).name
94
- if command in {"exec", "command"}:
96
+ if allow_shell_builtins and command in {"exec", "command"}:
95
97
  if command == "command" and any(argument in {"-v", "-V"} for argument in current[1:2]):
96
98
  return current
97
99
  current = current[_command_wrapper_index(current, command) :]
98
100
  continue
99
- if command not in _WRAPPER_VALUES:
101
+ if command not in _WRAPPER_VALUES or (allowed_wrappers is not None and command not in allowed_wrappers):
100
102
  return current
101
103
  current = current[_value_wrapper_index(current, command) :]
102
104
  msg = "command wrapper nesting exceeds analysis bound"
@@ -120,25 +122,69 @@ def _command_wrapper_index(arguments: Sequence[str], command: str) -> int:
120
122
 
121
123
 
122
124
  def _value_wrapper_index(arguments: Sequence[str], command: str) -> int:
125
+ if command == "env":
126
+ return _env_wrapper_index(arguments)
123
127
  index = 1
124
128
  while index < len(arguments):
125
129
  argument = arguments[index]
126
130
  if argument == "--":
127
131
  index += 1
128
132
  break
129
- if command == "env" and re.match(r"^[A-Za-z_][A-Za-z0-9_]*=", argument):
130
- index += 1
131
- continue
132
133
  if not argument.startswith("-") or argument == "-":
133
134
  break
134
- if command == "env" and argument in {"-S", "--split-string"}:
135
- msg = "env split-string has a separate unproven quoting grammar"
136
- raise UnprovableCommandError(msg)
137
135
  index += 2 if argument in _WRAPPER_VALUES[command] else 1
138
136
  # Timeout's positional duration precedes its executable.
139
137
  return index + int(command == "timeout")
140
138
 
141
139
 
140
+ def _env_wrapper_index(arguments: Sequence[str]) -> int:
141
+ index = 1
142
+ while index < len(arguments) and arguments[index].startswith("-"):
143
+ argument = arguments[index]
144
+ if argument == "-":
145
+ index += 1
146
+ break
147
+ if argument == "--":
148
+ index += 1
149
+ break
150
+ index += _env_option_size(arguments, index)
151
+ # Assignments follow options, including after --; later option-looking words
152
+ # are executable operands, not additional env options.
153
+ while index < len(arguments) and "=" in arguments[index]:
154
+ if arguments[index].startswith("="):
155
+ msg = "env assignment requires a nonempty variable name"
156
+ raise UnprovableCommandError(msg)
157
+ index += 1
158
+ return index
159
+
160
+
161
+ def _env_option_size(arguments: Sequence[str], index: int) -> int:
162
+ argument = arguments[index]
163
+ if argument in {"--help", "--version"}:
164
+ return len(arguments) - index # GNU env terminates without executing operands.
165
+ if argument in {"-S", "--split-string"} or argument.startswith(("-S", "--split-string=")):
166
+ msg = "env split-string has a separate unproven quoting grammar"
167
+ raise UnprovableCommandError(msg)
168
+ if argument in {"-i", "--ignore-environment", "-v", "--debug"}:
169
+ return 1
170
+ if argument in _WRAPPER_VALUES["env"]:
171
+ value = arguments[index + 1] if index + 1 < len(arguments) else ""
172
+ _validate_env_operand(argument, value)
173
+ return 2
174
+ for option in ("--unset=", "--chdir=", "-u", "-C"):
175
+ if argument.startswith(option):
176
+ _validate_env_operand(option, argument[len(option) :])
177
+ return 1
178
+ msg = "unsupported env wrapper option"
179
+ raise UnprovableCommandError(msg)
180
+
181
+
182
+ def _validate_env_operand(option: str, value: str) -> None:
183
+ if not value or (option in {"-u", "--unset", "--unset="} and "=" in value):
184
+ msg = "env option requires a valid value"
185
+ raise UnprovableCommandError(msg)
186
+
187
+
142
188
  def is_python_executable(executable: str) -> bool:
143
189
  return re.fullmatch(r"python(?:[23](?:\.\d+)?)?", PurePosixPath(executable).name) is not None
144
190
 
@@ -175,6 +221,11 @@ def _python(arguments: Sequence[str]) -> InterpreterInvocation:
175
221
  if boundary is not None:
176
222
  return boundary
177
223
  argument = arguments[index]
224
+ if argument == "--check-hash-based-pycs":
225
+ if _following_operand(arguments, index) not in {"default", "always", "never"}:
226
+ return InterpreterInvocation("unknown")
227
+ index += 2
228
+ continue
178
229
  if argument.startswith("--"):
179
230
  return InterpreterInvocation(
180
231
  "external"
@@ -29,7 +29,7 @@ _POLICIES: Final = frozenset(
29
29
  )
30
30
  _WAIT_MODULES: Final = frozenset({"tenacity", "tenacity.wait"})
31
31
  _WALL_CLOCK_SLEEPS: Final = frozenset(
32
- {"asyncio.sleep", "anyio.sleep", "trio.sleep", "time.sleep", "tenacity.nap.sleep"}
32
+ {"asyncio.sleep", "anyio.sleep", "trio.sleep", "time.sleep", "tenacity.sleep", "tenacity.nap.sleep"}
33
33
  )
34
34
  _MESSAGE: Final = (
35
35
  "this tenacity policy waits between attempts on the wall clock without a sleep= seam; pass an injected sleep "
@@ -58,8 +58,8 @@ class RequireInjectableRetrySleep(Rule):
58
58
  autofix=AutofixPolicy.NONE,
59
59
  limitations=(
60
60
  "Only calls to tenacity.retry, tenacity.Retrying, and tenacity.AsyncRetrying resolved through imports are inspected; bare @retry, positional arguments, and **kwargs expansion abstain.",
61
- "A wait is reported only when it is built inline from tenacity wait_* calls, optionally combined with +; wait_none() and wait_fixed(0) do not wait. A wait read from a name, attribute, or other call is treated as injected.",
62
- "Any sleep= argument other than a wall-clock sleep imported from asyncio, anyio, trio, time, or tenacity.nap counts as a seam; the rule does not prove that tests replace it.",
61
+ "A wait is reported only when it is built inline from tenacity wait_* calls, optionally combined with +; wait_none(), literal-zero wait_fixed and wait_random calls, and known zero-only wait_combine or wait_chain calls do not wait. A wait read from a name, attribute, or other call is treated as injected.",
62
+ "Any sleep= argument other than a wall-clock sleep imported from asyncio, anyio, trio, time, tenacity, or tenacity.nap counts as a seam; the rule does not prove that tests replace it.",
63
63
  "The backoff library has no sleep parameter, so its decorators are not inspected. Test modules, test directories, conftest.py, test-support paths, and generated files are excluded.",
64
64
  ),
65
65
  examples=(
@@ -143,20 +143,55 @@ def _waits_without_seam(call: ast.Call, imports: ImportIndex) -> bool:
143
143
  def _wait_strategy(node: ast.expr, imports: ImportIndex) -> bool | None:
144
144
  match node:
145
145
  case ast.BinOp(left=left, op=ast.Add(), right=right):
146
- parts = (_wait_strategy(left, imports), _wait_strategy(right, imports))
147
- return None if None in parts else any(parts)
146
+ return _combined_waits((left, right), imports)
148
147
  case ast.Call(func=func, args=args, keywords=keywords):
149
148
  module, _, strategy = (imports.resolved_qualified_name(func) or "").rpartition(".")
150
149
  if module not in _WAIT_MODULES or not strategy.startswith("wait_"):
151
150
  return None
152
- match strategy, args, keywords:
153
- case "wait_none", [], []:
154
- return False
155
- case "wait_fixed", [ast.Constant(value=0)], []:
156
- return False
157
- case "wait_fixed", [], [ast.keyword(arg="wait", value=ast.Constant(value=0))]:
158
- return False
159
- case _:
160
- return True
151
+ return _wait_constructor(strategy, args, keywords, imports)
161
152
  case _:
162
153
  return None
154
+
155
+
156
+ def _wait_constructor(
157
+ strategy: str, args: list[ast.expr], keywords: list[ast.keyword], imports: ImportIndex
158
+ ) -> bool | None:
159
+ match strategy, args, keywords:
160
+ case "wait_none", [], []:
161
+ return False
162
+ case ("wait_fixed", [value], []) | ("wait_fixed", [], [ast.keyword(arg="wait", value=value)]):
163
+ return not _literal_zero(value)
164
+ case "wait_random", _, _:
165
+ return _random_waits(args, keywords)
166
+ case "wait_combine" | "wait_chain", _, _:
167
+ if keywords or any(isinstance(argument, ast.Starred) for argument in args):
168
+ return None
169
+ if strategy == "wait_chain" and not args:
170
+ return None
171
+ return _combined_waits(tuple(args), imports)
172
+ case _:
173
+ return True
174
+
175
+
176
+ def _combined_waits(nodes: tuple[ast.expr, ...], imports: ImportIndex) -> bool | None:
177
+ parts = tuple(_wait_strategy(node, imports) for node in nodes)
178
+ return None if None in parts else any(parts)
179
+
180
+
181
+ def _random_waits(args: list[ast.expr], keywords: list[ast.keyword]) -> bool | None:
182
+ names = ("min", "max")
183
+ if len(args) > len(names) or any(isinstance(argument, ast.Starred) for argument in args):
184
+ return None
185
+ values = dict(zip(names, args, strict=False))
186
+ for keyword in keywords:
187
+ if keyword.arg not in names or keyword.arg in values:
188
+ return None
189
+ values[keyword.arg] = keyword.value
190
+ return not (("min" not in values or _literal_zero(values["min"])) and _literal_zero(values.get("max")))
191
+
192
+
193
+ def _literal_zero(node: ast.expr | None) -> bool:
194
+ if isinstance(node, ast.UnaryOp) and isinstance(node.op, (ast.UAdd, ast.USub)):
195
+ operand = node.operand
196
+ return isinstance(operand, ast.Constant) and isinstance(operand.value, (int, float)) and operand.value == 0
197
+ return isinstance(node, ast.Constant) and node.value == 0