sarj-python-lint 1.7.5__tar.gz → 1.7.7__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 (164) hide show
  1. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/PKG-INFO +1 -1
  2. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/pyproject.toml +1 -1
  3. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_registry.py +2 -0
  4. sarj_python_lint-1.7.7/src/sarj_python_lint/rules/discourage_nullable_constructor_parameters.py +122 -0
  5. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +2 -1
  6. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/.gitignore +0 -0
  7. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/LICENSE +0 -0
  8. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/README.md +0 -0
  9. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/__init__.py +0 -0
  10. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/__main__.py +0 -0
  11. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/_analysis_session.py +0 -0
  12. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/_file_context.py +0 -0
  13. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/_filesystem.py +0 -0
  14. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/_python_target.py +0 -0
  15. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/_ratchet_cli.py +0 -0
  16. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/_secret_names.py +0 -0
  17. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/_version.py +0 -0
  18. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/benchmark.py +0 -0
  19. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/json_boundary.py +0 -0
  20. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/py.typed +0 -0
  21. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/ratchet.py +0 -0
  22. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rule_base.py +0 -0
  23. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/__init__.py +0 -0
  24. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
  25. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_ast_index.py +0 -0
  26. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_ast_position.py +0 -0
  27. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_comments.py +0 -0
  28. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
  29. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
  30. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_docstrings.py +0 -0
  31. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_fastapi.py +0 -0
  32. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_first_party.py +0 -0
  33. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
  34. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_imports.py +0 -0
  35. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_logging.py +0 -0
  36. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
  37. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_paths.py +0 -0
  38. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_project_index.py +0 -0
  39. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
  40. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_pytest.py +0 -0
  41. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
  42. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_set_fields.py +0 -0
  43. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_sql.py +0 -0
  44. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
  45. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
  46. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/_test_composition.py +0 -0
  47. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
  48. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
  49. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
  50. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
  51. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
  52. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
  53. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
  54. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
  55. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
  56. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
  57. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
  58. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
  59. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
  60. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
  61. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
  62. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
  63. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
  64. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
  65. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
  66. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
  67. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
  68. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
  69. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
  70. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
  71. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
  72. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
  73. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
  74. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
  75. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
  76. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
  77. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
  78. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
  79. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
  80. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
  81. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
  82. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
  83. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
  84. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
  85. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
  86. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
  87. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
  88. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
  89. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
  90. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
  91. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
  92. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
  93. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_select_star.py +0 -0
  94. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
  95. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
  96. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
  97. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
  98. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
  99. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
  100. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
  101. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
  102. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
  103. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
  104. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
  105. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
  106. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
  107. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
  108. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
  109. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
  110. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
  111. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
  112. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
  113. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
  114. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
  115. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
  116. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
  117. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
  118. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
  119. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
  120. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
  121. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
  122. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
  123. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
  124. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
  125. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
  126. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
  127. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
  128. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
  129. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
  130. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
  131. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
  132. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
  133. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
  134. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
  135. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
  136. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
  137. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
  138. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
  139. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
  140. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
  141. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
  142. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
  143. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
  144. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
  145. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
  146. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
  147. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
  148. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
  149. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
  150. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
  151. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
  152. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
  153. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
  154. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
  155. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/stepdown.py +0 -0
  156. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
  157. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
  158. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
  159. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
  160. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
  161. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
  162. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
  163. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
  164. {sarj_python_lint-1.7.5 → sarj_python_lint-1.7.7}/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.7.5
3
+ Version: 1.7.7
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.7.5"
3
+ version = "1.7.7"
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" }]
@@ -9,6 +9,7 @@ from sarj_python_lint.rules.complex_postgres_query_requires_architecture_review
9
9
  ComplexPostgresQueryRequiresArchitectureReview,
10
10
  )
11
11
  from sarj_python_lint.rules.defect_xfail_requires_explicit_strict import DefectXfailRequiresExplicitStrict
12
+ from sarj_python_lint.rules.discourage_nullable_constructor_parameters import DiscourageNullableConstructorParameters
12
13
  from sarj_python_lint.rules.docstring_args_restate_signature import (
13
14
  DocstringArgsRestateSignature,
14
15
  )
@@ -192,6 +193,7 @@ if TYPE_CHECKING:
192
193
  REGISTRY: Mapping[str, type[Rule]] = MappingProxyType(
193
194
  {
194
195
  RequireExplicitContractImplementation.id: RequireExplicitContractImplementation,
196
+ DiscourageNullableConstructorParameters.id: DiscourageNullableConstructorParameters,
195
197
  RequirePublicDependencyContract.id: RequirePublicDependencyContract,
196
198
  RequireExplicitServiceContract.id: RequireExplicitServiceContract,
197
199
  AsyncCleanupRegisteredSynchronously.id: AsyncCleanupRegisteredSynchronously,
@@ -0,0 +1,122 @@
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
+ )
18
+ from sarj_python_lint.rules._paths import is_test_path
19
+
20
+
21
+ if TYPE_CHECKING:
22
+ from sarj_python_lint._file_context import PythonFileContext
23
+
24
+
25
+ @final
26
+ class DiscourageNullableConstructorParameters(Rule):
27
+ id = "discourage-nullable-constructor-parameters"
28
+ code = "SARJ468"
29
+ documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
30
+ default_level=Severity.WARNING,
31
+ summary="Avoid nullable constructor parameters when a non-nullable interface can express the choice.",
32
+ rationale=(
33
+ "Nullable constructor parameters allow partially configured objects and force callers and implementations "
34
+ "to handle an absent value. Required nullable parameters still permit this state."
35
+ ),
36
+ remediation="Prefer a non-nullable dependency or a separate constructor for the absent case; suppress deliberate nullable values with a reason.",
37
+ category=RuleCategory.ARCHITECTURE,
38
+ autofix=AutofixPolicy.NONE,
39
+ limitations=(
40
+ "Only explicitly annotated `__init__` parameters using PEP 604 unions containing None are checked.",
41
+ "Tests and generated files are excluded; genuinely absent domain values may justify a suppression.",
42
+ ),
43
+ examples=(
44
+ RuleExample(
45
+ example_id="nullable-dependency",
46
+ title="Constructor permits a missing dependency",
47
+ outcome=ExampleOutcome.MATCH,
48
+ files=(
49
+ ExampleFile.python(
50
+ "app/service.py",
51
+ "class Service:\n def __init__(self, store: Store | None = None) -> None:\n"
52
+ " self.store = store\n",
53
+ ),
54
+ ),
55
+ focus_path=PurePosixPath("app/service.py"),
56
+ expected_count=1,
57
+ public=True,
58
+ ),
59
+ RuleExample(
60
+ example_id="non-nullable-dependency",
61
+ title="Constructor requires a usable dependency",
62
+ outcome=ExampleOutcome.NO_MATCH,
63
+ files=(
64
+ ExampleFile.python(
65
+ "app/service.py",
66
+ "class Service:\n def __init__(self, store: Store) -> None:\n self.store = store\n",
67
+ ),
68
+ ),
69
+ focus_path=PurePosixPath("app/service.py"),
70
+ expected_count=0,
71
+ public=True,
72
+ ),
73
+ ),
74
+ )
75
+ description = documentation.summary
76
+
77
+ @override
78
+ def check_context(self, context: PythonFileContext) -> list[Diagnostic]:
79
+ if context.generated or context.tree is None or is_test_path(context.path):
80
+ return []
81
+ findings: list[Diagnostic] = []
82
+ for node in ast.walk(context.tree):
83
+ if not isinstance(node, ast.ClassDef):
84
+ continue
85
+ for method in node.body:
86
+ if not isinstance(method, ast.FunctionDef | ast.AsyncFunctionDef) or method.name != "__init__":
87
+ continue
88
+ positional = method.args.posonlyargs + method.args.args
89
+ for parameter in (*positional, *method.args.kwonlyargs):
90
+ self._append_if_nullable(context, parameter, findings)
91
+ return findings
92
+
93
+ def _append_if_nullable(
94
+ self,
95
+ context: PythonFileContext,
96
+ parameter: ast.arg,
97
+ findings: list[Diagnostic],
98
+ ) -> None:
99
+ if parameter.annotation is None or not _is_nullable_union(parameter.annotation):
100
+ return
101
+ findings.append(
102
+ Diagnostic(
103
+ path=context.path,
104
+ line=parameter.lineno,
105
+ col=parameter.col_offset + 1,
106
+ code=self.code,
107
+ severity=Severity.WARNING,
108
+ message=f"Constructor parameter `{parameter.arg}` accepts None; prefer a non-nullable interface.",
109
+ )
110
+ )
111
+
112
+
113
+ def _is_nullable_union(annotation: ast.expr) -> bool:
114
+ if not isinstance(annotation, ast.BinOp) or not isinstance(annotation.op, ast.BitOr):
115
+ return False
116
+ return _is_none_union_member(annotation.left) or _is_none_union_member(annotation.right)
117
+
118
+
119
+ def _is_none_union_member(annotation: ast.expr) -> bool:
120
+ if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
121
+ return _is_none_union_member(annotation.left) or _is_none_union_member(annotation.right)
122
+ return isinstance(annotation, ast.Constant) and annotation.value is None
@@ -52,7 +52,7 @@ class PreferSetIsdisjoint(ProjectRule):
52
52
  id = "prefer-set-isdisjoint"
53
53
  code = "SARJ431"
54
54
  documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
55
- default_level=Severity.WARNING,
55
+ default_level=Severity.ERROR,
56
56
  summary="Prefer `set.isdisjoint` when a built-in set intersection is used only as a boolean predicate.",
57
57
  rationale="`isdisjoint` names the overlap predicate directly and avoids allocating an intersection that is immediately discarded.",
58
58
  remediation="Use `left.isdisjoint(right)` and negate it when the condition requires overlap.",
@@ -70,6 +70,7 @@ class PreferSetIsdisjoint(ProjectRule):
70
70
  title="A declared set field is used only for an overlap test",
71
71
  outcome=ExampleOutcome.MATCH,
72
72
  files=(
73
+ ExampleFile(PurePosixPath("pyproject.toml"), '[project]\nname = "example"\nversion = "0.1.0"\n'),
73
74
  ExampleFile.python(
74
75
  "app/policy.py",
75
76
  "class AccessCase:\n tags: frozenset[str]\n\ndef accepts(case: AccessCase):\n if case.tags & {'read', 'write'}:\n allow()\n",