sarj-python-lint 1.46.0__tar.gz → 1.46.2__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 (215) hide show
  1. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/PKG-INFO +1 -1
  2. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/pyproject.toml +1 -1
  3. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_ast_index.py +5 -1
  4. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +17 -8
  5. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_str_enum.py +82 -16
  6. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/.gitignore +0 -0
  7. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/LICENSE +0 -0
  8. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/README.md +0 -0
  9. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/__init__.py +0 -0
  10. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/__main__.py +0 -0
  11. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/_analysis_session.py +0 -0
  12. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/_file_context.py +0 -0
  13. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/_filesystem.py +0 -0
  14. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/_python_target.py +0 -0
  15. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/_ratchet_cli.py +0 -0
  16. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/_secret_names.py +0 -0
  17. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/_source.py +0 -0
  18. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/_version.py +0 -0
  19. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/benchmark.py +0 -0
  20. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/interpreter_argv.py +0 -0
  21. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/json_boundary.py +0 -0
  22. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/py.typed +0 -0
  23. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/ratchet.py +0 -0
  24. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rule_base.py +0 -0
  25. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/__init__.py +0 -0
  26. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
  27. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_ast_position.py +0 -0
  28. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_closed_helpers.py +0 -0
  29. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_comments.py +0 -0
  30. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
  31. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_copy_on_write.py +0 -0
  32. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
  33. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_docstrings.py +0 -0
  34. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_exports.py +0 -0
  35. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_fastapi.py +0 -0
  36. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_first_party.py +0 -0
  37. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
  38. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_imports.py +0 -0
  39. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_inert_model_annotation.py +0 -0
  40. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_inherited_contract.py +0 -0
  41. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_local_source.py +0 -0
  42. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_logging.py +0 -0
  43. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_namespace_access.py +0 -0
  44. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_native_namespace_capability.py +0 -0
  45. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
  46. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_paths.py +0 -0
  47. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_project_index.py +0 -0
  48. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
  49. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_pydantic_field_contract.py +0 -0
  50. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_pytest.py +0 -0
  51. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_registry.py +0 -0
  52. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_resolved_operation_signature.py +0 -0
  53. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
  54. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_set_fields.py +0 -0
  55. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_sql.py +0 -0
  56. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_static_json_alias.py +0 -0
  57. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
  58. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
  59. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_test_composition.py +0 -0
  60. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_test_provenance.py +0 -0
  61. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/_type_guard_symbols.py +0 -0
  62. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
  63. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
  64. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
  65. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
  66. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
  67. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
  68. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/duplicate_adjacent_exception_handler.py +0 -0
  69. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/duplicate_closed_pure_helper.py +0 -0
  70. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
  71. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
  72. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
  73. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
  74. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
  75. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
  76. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
  77. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
  78. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
  79. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
  80. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
  81. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_async_function_cache.py +0 -0
  82. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_before_validator_input_mutation.py +0 -0
  83. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_broad_keyword_capture.py +0 -0
  84. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
  85. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_conflicting_pydantic_alias_validation.py +0 -0
  86. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
  87. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_contradictory_type_guard.py +0 -0
  88. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
  89. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
  90. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
  91. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
  92. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
  93. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
  94. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
  95. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
  96. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
  97. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
  98. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
  99. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_fixed_sleep_in_loop.py +0 -0
  100. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
  101. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
  102. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
  103. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_impossible_pydantic_field_bounds.py +0 -0
  104. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
  105. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_input_model_mutation.py +0 -0
  106. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_interpreter_source_arguments.py +0 -0
  107. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
  108. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_invalid_pydantic_bypass.py +0 -0
  109. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_invalid_pydantic_validator_return.py +0 -0
  110. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_loguru_exc_info.py +0 -0
  111. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_loguru_printf_format.py +0 -0
  112. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_mocked_pydantic_value_object.py +0 -0
  113. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
  114. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
  115. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
  116. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_partial_type_is.py +0 -0
  117. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
  118. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
  119. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
  120. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
  121. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
  122. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
  123. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
  124. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
  125. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
  126. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
  127. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
  128. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_select_star.py +0 -0
  129. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
  130. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
  131. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_shallow_record_type_guard.py +0 -0
  132. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
  133. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
  134. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
  135. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_test_method_grafting.py +0 -0
  136. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
  137. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
  138. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_unknown_pydantic_validator_field.py +0 -0
  139. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
  140. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_unused_copy_result.py +0 -0
  141. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +0 -0
  142. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
  143. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
  144. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
  145. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
  146. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
  147. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
  148. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +0 -0
  149. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
  150. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
  151. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
  152. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_declarative_batch_validation.py +0 -0
  153. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_discriminated_model_union.py +0 -0
  154. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
  155. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
  156. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
  157. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
  158. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
  159. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
  160. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
  161. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
  162. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
  163. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
  164. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
  165. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
  166. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_native_string_check.py +0 -0
  167. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
  168. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
  169. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
  170. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +0 -0
  171. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
  172. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_required_constructor_parameters.py +0 -0
  173. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
  174. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
  175. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
  176. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
  177. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
  178. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
  179. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
  180. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
  181. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
  182. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
  183. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
  184. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
  185. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
  186. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/redundant_test_constructor_forwarder.py +0 -0
  187. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
  188. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
  189. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
  190. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/repeated_unimplemented_test_contract.py +0 -0
  191. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
  192. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
  193. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
  194. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/require_injectable_retry_sleep.py +0 -0
  195. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
  196. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
  197. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
  198. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/require_precise_factory_signature.py +0 -0
  199. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
  200. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
  201. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
  202. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
  203. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
  204. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
  205. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/stepdown.py +0 -0
  206. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
  207. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
  208. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
  209. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/test_without_explicit_oracle.py +0 -0
  210. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
  211. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
  212. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
  213. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
  214. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
  215. {sarj_python_lint-1.46.0 → sarj_python_lint-1.46.2}/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.46.0
3
+ Version: 1.46.2
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.46.0"
3
+ version = "1.46.2"
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" }]
@@ -58,7 +58,11 @@ def walk(node: ast.AST, *, index: NodeIndex | None = None) -> Iterator[ast.AST]:
58
58
  if index is not None and index.tree is node:
59
59
  yield from index.query((ast.AST,))
60
60
  return
61
- queue = deque((node,))
61
+ queue = children(node)
62
+ yield node
63
+ if not queue:
64
+ return
65
+ queue = deque(queue)
62
66
  while queue:
63
67
  current = queue.popleft()
64
68
  queue.extend(children(current))
@@ -442,14 +442,23 @@ def _role_keys(roles: list[_IdRole]) -> set[tuple[str, str]]:
442
442
 
443
443
 
444
444
  def _class_id_roles(node: ast.ClassDef, imports: ImportIndex, facts: _TypeFacts) -> list[_IdRole]:
445
- return [
446
- role
447
- for statement in node.body
448
- if isinstance(statement, ast.AnnAssign)
449
- and isinstance(statement.target, ast.Name)
450
- and not _has_pydantic_wire_alias(statement, imports)
451
- if (role := _role(statement.target.id, statement.annotation, imports, facts, allow_bare_id=True)) is not None
452
- ]
445
+ roles: dict[str, _IdRole | None] = {}
446
+ for statement in node.body:
447
+ if not isinstance(statement, ast.AnnAssign) or not isinstance(statement.target, ast.Name):
448
+ continue
449
+ name = statement.target.id
450
+ role = (
451
+ None
452
+ if _has_pydantic_wire_alias(statement, imports)
453
+ else _role(name, statement.annotation, imports, facts, allow_bare_id=True)
454
+ )
455
+ previous = roles.get(name)
456
+ # The final annotation owns the field. Equivalent redeclarations retain
457
+ # the existing diagnostic anchor and its exact local suppression.
458
+ if role is not None and previous is not None and role.carrier == previous.carrier:
459
+ continue
460
+ roles[name] = role
461
+ return [role for role in roles.values() if role is not None]
453
462
 
454
463
 
455
464
  def _has_pydantic_wire_alias(statement: ast.AnnAssign, imports: ImportIndex) -> bool:
@@ -39,6 +39,8 @@ _MIN_TYPE_ALIAS_ARGS = 2
39
39
  _CHOICE_PAIR_ARITY = 2
40
40
  _CAST_FUNCTION = "cast"
41
41
  _STR_CONSTRUCTOR = "str"
42
+ _TYPING_SOURCES = frozenset({"typing", "typing_extensions"})
43
+ _NAMESPACE_ACCESS_MEMBERS = frozenset({"__dict__", "__getattribute__", "__setattr__", "__delattr__"})
42
44
 
43
45
 
44
46
  class _LiteralAliases(NamedTuple):
@@ -62,6 +64,12 @@ class _ClassFieldDiagnostics:
62
64
  member_keys: dict[int, set[str]]
63
65
 
64
66
 
67
+ @dataclass(frozen=True, slots=True)
68
+ class _TypingNamespaceOrigins:
69
+ namespaces: frozenset[str]
70
+ handles: frozenset[str]
71
+
72
+
65
73
  #: Sibling class attributes whose presence marks all raw-str fields as choice-like.
66
74
  CHOICES_ATTR_NAMES = frozenset({"choices", "states", "statuses", "values", "allowed"})
67
75
 
@@ -363,6 +371,7 @@ class PreferStrEnum(Rule):
363
371
  class_choice_signal = "str" in signals and any(name in signals.lower() for name in CHOICES_ATTR_NAMES)
364
372
  wrapper_signal = any(symbol in signals for symbol in ("Annotated", "Optional", "Union"))
365
373
  imports = context.imports if class_choice_signal or "assert_never" in signals or wrapper_signal else None
374
+ rejection_imports = _assert_never_imports(context, imports)
366
375
  test_path = is_test_path(path)
367
376
  check_clusters = not test_path
368
377
  literal_aliases = _module_literal_aliases(tree)
@@ -423,7 +432,9 @@ class PreferStrEnum(Rule):
423
432
  all_clusters.append((child_active, opaque, owned_attributes))
424
433
  cluster_opacity[id(child_active)] = opaque
425
434
  cluster_owned_attributes[id(child_active)] = owned_attributes
426
- cluster_closed_nodes[id(child_active)] = _closed_domain_node_ids(node, imports, closed_collections)
435
+ cluster_closed_nodes[id(child_active)] = _closed_domain_node_ids(
436
+ node, rejection_imports, closed_collections
437
+ )
427
438
  inherited_method = cluster_methods.get(id(active))
428
439
  if not _OWNED_ROOTS.isdisjoint(shadowed):
429
440
  inherited_method = None
@@ -513,7 +524,7 @@ class PreferStrEnum(Rule):
513
524
  elif isinstance(node, ast.Match) and id(node) in cluster_closed_nodes.get(
514
525
  id(active), frozenset()
515
526
  ):
516
- _accumulate_match(active, node, imports)
527
+ _accumulate_match(active, node, rejection_imports)
517
528
  schedule_children(stack, node, active, child_active)
518
529
 
519
530
  collect_clusters()
@@ -642,6 +653,56 @@ def _has_str_enum_signal(source: str) -> bool:
642
653
  )
643
654
 
644
655
 
656
+ def _assert_never_imports(context: PythonFileContext, imports: ImportIndex | None) -> ImportIndex | None:
657
+ if imports is None or "assert_never" not in context.symbol_source:
658
+ return imports
659
+ origins = _typing_namespace_origins(context)
660
+ for node in context.nodes(ast.Name, ast.Attribute):
661
+ parent = context.parents.get(node)
662
+ if isinstance(node, ast.Name) and isinstance(node.ctx, ast.Load) and node.id in origins.handles:
663
+ return None
664
+ if _typing_namespace_exposed(node, parent, origins.namespaces):
665
+ return None
666
+ if (
667
+ isinstance(node.ctx, ast.Load)
668
+ and imports.resolves(node, sources=_TYPING_SOURCES, symbol="assert_never")
669
+ and (not isinstance(parent, ast.Call) or parent.func is not node)
670
+ ):
671
+ return None
672
+ return imports
673
+
674
+
675
+ def _typing_namespace_origins(context: PythonFileContext) -> _TypingNamespaceOrigins:
676
+ namespaces: set[str] = set()
677
+ handles: set[str] = set()
678
+ for node in context.nodes(ast.Import):
679
+ namespaces.update(alias.asname or alias.name for alias in node.names if alias.name in _TYPING_SOURCES)
680
+ for node in context.nodes(ast.ImportFrom):
681
+ if node.level == 0 and node.module in _TYPING_SOURCES:
682
+ handles.update(
683
+ alias.asname or alias.name for alias in node.names if alias.name in _NAMESPACE_ACCESS_MEMBERS
684
+ )
685
+ return _TypingNamespaceOrigins(frozenset(namespaces), frozenset(handles))
686
+
687
+
688
+ def _typing_namespace_exposed(node: ast.AST, parent: ast.AST | None, namespaces: frozenset[str]) -> bool:
689
+ if isinstance(node, ast.Name) and isinstance(node.ctx, ast.Load) and node.id in namespaces:
690
+ return not isinstance(parent, ast.Attribute) or parent.value is not node
691
+ if (
692
+ isinstance(node, ast.Attribute)
693
+ and isinstance(node.value, ast.Name)
694
+ and node.value.id in namespaces
695
+ and node.attr in _NAMESPACE_ACCESS_MEMBERS
696
+ ):
697
+ return True
698
+ if not isinstance(node, ast.Attribute) or not isinstance(node.ctx, (ast.Store, ast.Del)):
699
+ return False
700
+ root: ast.expr = node
701
+ while isinstance(root, ast.Attribute):
702
+ root = root.value
703
+ return isinstance(root, ast.Name) and root.id in namespaces
704
+
705
+
645
706
  def _enum_like_class_ids(tree: ast.Module, *, node_index: NodeIndex | None = None) -> frozenset[int]:
646
707
  enum_names = set(_ENUM_BASE_NAMES)
647
708
  enum_modules = {"enum"}
@@ -1423,13 +1484,7 @@ def _unsafe_attribute_collection_uses(tree: ast.AST, *, node_index: NodeIndex |
1423
1484
  def _propagate_collection_alias_uses(
1424
1485
  tree: ast.AST, unsafe: dict[str, set[str]], *, node_index: NodeIndex | None = None
1425
1486
  ) -> None:
1426
- aliases = [
1427
- (target.id, node.value.id)
1428
- for node in walk_ast(tree, index=node_index)
1429
- if isinstance(node, ast.Assign) and isinstance(node.value, ast.Name)
1430
- for target in node.targets
1431
- if isinstance(target, ast.Name)
1432
- ]
1487
+ aliases = _collection_owner_aliases(tree, node_index=node_index)
1433
1488
  # Exposure invalidates proof even when an alias has other possible bindings.
1434
1489
  # The finite owner/attribute sets converge without following runtime values.
1435
1490
  for _round in range(len(aliases)):
@@ -1443,6 +1498,16 @@ def _propagate_collection_alias_uses(
1443
1498
  break
1444
1499
 
1445
1500
 
1501
+ def _collection_owner_aliases(tree: ast.AST, *, node_index: NodeIndex | None) -> list[tuple[str, str]]:
1502
+ aliases: list[tuple[str, str]] = []
1503
+ for node in walk_ast(tree, index=node_index):
1504
+ if isinstance(node, ast.Assign) and isinstance(node.value, ast.Name):
1505
+ aliases.extend((target.id, node.value.id) for target in node.targets if isinstance(target, ast.Name))
1506
+ elif isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name) and isinstance(node.value, ast.Name):
1507
+ aliases.append((node.target.id, node.value.id))
1508
+ return aliases
1509
+
1510
+
1446
1511
  def _string_collection_values(node: ast.AST | None) -> set[str] | None:
1447
1512
  if isinstance(node, ast.Dict):
1448
1513
  return _dictionary_choice_values(node)
@@ -1792,18 +1857,19 @@ def _str_const(node: ast.AST) -> str | None:
1792
1857
  def _class_choice_fields(
1793
1858
  cls: ast.ClassDef, raw_string_aliases: frozenset[str], imports: ImportIndex
1794
1859
  ) -> list[tuple[ast.AnnAssign, str, str | None]]:
1795
- candidates: list[tuple[ast.AnnAssign, str, str | None]] = []
1860
+ candidates: dict[str, tuple[ast.AnnAssign, str, str | None] | None] = {}
1796
1861
  for stmt in cls.body:
1797
- if not isinstance(stmt, ast.AnnAssign):
1798
- continue
1799
- if not isinstance(stmt.target, ast.Name):
1862
+ if not isinstance(stmt, ast.AnnAssign) or not isinstance(stmt.target, ast.Name):
1800
1863
  continue
1864
+ name = stmt.target.id
1801
1865
  if not _is_choice_string_annotation(stmt.annotation, raw_string_aliases, imports):
1866
+ candidates[name] = None
1802
1867
  continue
1803
- name = stmt.target.id
1804
1868
  default = _str_const(stmt.value) if stmt.value is not None else None
1805
- candidates.append((stmt, name, default))
1806
- return candidates
1869
+ previous = candidates.get(name)
1870
+ if previous is None or previous[2] != default:
1871
+ candidates[name] = (stmt, name, default)
1872
+ return [candidate for candidate in candidates.values() if candidate is not None]
1807
1873
 
1808
1874
 
1809
1875
  def _is_wire_call(value: ast.Call, callee: ast.expr, args: list[ast.expr], blocked_call_names: frozenset[str]) -> bool: