sarj-python-lint 0.87.2__tar.gz → 0.87.4__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.
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/PKG-INFO +1 -1
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/pyproject.toml +1 -1
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/__main__.py +6 -11
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/_ratchet_cli.py +2 -2
- sarj_python_lint-0.87.4/src/sarj_python_lint/json_boundary.py +10 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/ratchet.py +6 -9
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rule_base.py +3 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/fakes_in_shared_location.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/iac_source_coupled_test.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/mock_without_spec.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/named_record_at_boundaries.py +2 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_any_mapping_types.py +2 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +2 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_redundant_literal_description.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +2 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_restated_comment.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_typed_doc_sections.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_unused_value_marker.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/over_mocked_test.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +2 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_library_fake.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_module_level_constant.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_or_pattern.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +2 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +2 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +2 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +2 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +2 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/redundant_docstring.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/repeated_static_call_cases.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/require_port_for_service.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/typed_error_reasons.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/unused_test_factory_option.py +1 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/.gitignore +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/LICENSE +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/README.md +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/__init__.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/_analysis_session.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/_filesystem.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/_python_target.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/_secret_names.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/_version.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/py.typed +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/__init__.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_ast_index.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_ast_position.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_comments.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_docstrings.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_fastapi.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_first_party.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_imports.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_logging.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_paths.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_project_index.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_pytest.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_registry.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_sql.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_select_star.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/require_typed_http_test_response.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/stepdown.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
- {sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sarj-python-lint
|
|
3
|
-
Version: 0.87.
|
|
3
|
+
Version: 0.87.4
|
|
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/
|
|
@@ -14,6 +14,7 @@ import typer
|
|
|
14
14
|
from sarj_python_lint import __version__
|
|
15
15
|
from sarj_python_lint._analysis_session import AnalysisSession
|
|
16
16
|
from sarj_python_lint._filesystem import atomic_write_text
|
|
17
|
+
from sarj_python_lint.json_boundary import is_object_mapping, parse_json
|
|
17
18
|
from sarj_python_lint.rule_base import Diagnostic, ProjectRule, Rule, Severity, is_suppressed
|
|
18
19
|
from sarj_python_lint.rules import REGISTRY
|
|
19
20
|
from sarj_python_lint.rules._paths import clear_path_caches
|
|
@@ -335,20 +336,14 @@ def _baseline_path(path: Path, *, root: Path | None = None) -> str:
|
|
|
335
336
|
|
|
336
337
|
|
|
337
338
|
def _read_baseline(path: Path) -> dict[str, dict[str, int]]:
|
|
338
|
-
raw
|
|
339
|
-
|
|
340
|
-
)
|
|
341
|
-
if not isinstance(raw, dict):
|
|
339
|
+
raw = parse_json(path.read_text(encoding="utf-8"))
|
|
340
|
+
if not is_object_mapping(raw):
|
|
342
341
|
return {}
|
|
343
342
|
counts: dict[str, dict[str, int]] = {}
|
|
344
|
-
for file_key, per_code in raw.items():
|
|
345
|
-
if not isinstance(file_key, str) or not
|
|
343
|
+
for file_key, per_code in raw.items():
|
|
344
|
+
if not isinstance(file_key, str) or not is_object_mapping(per_code):
|
|
346
345
|
continue
|
|
347
|
-
counts[file_key] = {
|
|
348
|
-
code: n
|
|
349
|
-
for code, n in per_code.items() # pyright: ignore[reportUnknownVariableType] — same
|
|
350
|
-
if isinstance(code, str) and isinstance(n, int)
|
|
351
|
-
}
|
|
346
|
+
counts[file_key] = {code: n for code, n in per_code.items() if isinstance(code, str) and isinstance(n, int)}
|
|
352
347
|
return counts
|
|
353
348
|
|
|
354
349
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
import json
|
|
5
4
|
from pathlib import Path
|
|
6
5
|
import subprocess # ruff: ignore[suspicious-subprocess-import] -- fixed local Ruff introspection only
|
|
7
6
|
import sys
|
|
@@ -11,6 +10,7 @@ import typer
|
|
|
11
10
|
|
|
12
11
|
from sarj_python_lint._filesystem import atomic_write_text
|
|
13
12
|
from sarj_python_lint._version import __version__
|
|
13
|
+
from sarj_python_lint.json_boundary import parse_json
|
|
14
14
|
from sarj_python_lint.ratchet import (
|
|
15
15
|
DEFAULT_PER_FILE_CEILING,
|
|
16
16
|
Baseline,
|
|
@@ -142,7 +142,7 @@ def _ruff_selector_aliases() -> dict[str, str]:
|
|
|
142
142
|
encoding="utf-8",
|
|
143
143
|
text=True,
|
|
144
144
|
)
|
|
145
|
-
raw
|
|
145
|
+
raw = parse_json(completed.stdout)
|
|
146
146
|
if not _is_object_list(raw):
|
|
147
147
|
msg = "Ruff rule catalog was not a JSON list"
|
|
148
148
|
raise TypeError(msg)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import TypeIs
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def parse_json(text: str) -> object:
|
|
6
|
+
return json.loads(text) # pyright: ignore[reportAny] -- untyped stdlib parser boundary.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def is_object_mapping(value: object) -> TypeIs[dict[object, object]]:
|
|
10
|
+
return isinstance(value, dict)
|
|
@@ -9,6 +9,8 @@ import tokenize
|
|
|
9
9
|
from types import MappingProxyType
|
|
10
10
|
from typing import TYPE_CHECKING, Final, NamedTuple, TypeGuard
|
|
11
11
|
|
|
12
|
+
from sarj_python_lint.json_boundary import is_object_mapping, parse_json
|
|
13
|
+
|
|
12
14
|
|
|
13
15
|
if TYPE_CHECKING:
|
|
14
16
|
from collections.abc import Iterable, Iterator, Mapping
|
|
@@ -216,9 +218,7 @@ def seed(measurement: Measurement, baseline: Baseline) -> Baseline:
|
|
|
216
218
|
|
|
217
219
|
|
|
218
220
|
def load_baseline(path: Path) -> Baseline:
|
|
219
|
-
raw
|
|
220
|
-
path.read_text(encoding="utf-8")
|
|
221
|
-
)
|
|
221
|
+
raw = parse_json(path.read_text(encoding="utf-8"))
|
|
222
222
|
schema = _get(raw, "schema_version")
|
|
223
223
|
if schema is not None and schema != BASELINE_SCHEMA_VERSION:
|
|
224
224
|
msg = f"unsupported suppression baseline schema_version: {schema!r}"
|
|
@@ -238,9 +238,9 @@ def load_baseline(path: Path) -> Baseline:
|
|
|
238
238
|
|
|
239
239
|
|
|
240
240
|
def _get(mapping: object, key: str) -> object:
|
|
241
|
-
if not
|
|
241
|
+
if not is_object_mapping(mapping):
|
|
242
242
|
return None
|
|
243
|
-
return mapping.get(key)
|
|
243
|
+
return mapping.get(key)
|
|
244
244
|
|
|
245
245
|
|
|
246
246
|
def dump_baseline(baseline: Baseline, packages: Iterable[str]) -> str:
|
|
@@ -308,10 +308,7 @@ def _is_object_list(value: object) -> TypeGuard[list[object]]:
|
|
|
308
308
|
|
|
309
309
|
|
|
310
310
|
def _is_string_object_mapping(value: object) -> TypeGuard[dict[str, object]]:
|
|
311
|
-
return
|
|
312
|
-
isinstance(key, str)
|
|
313
|
-
for key in value # pyright: ignore[reportUnknownVariableType] — runtime validation narrows untyped JSON keys.
|
|
314
|
-
)
|
|
311
|
+
return is_object_mapping(value) and all(isinstance(key, str) for key in value)
|
|
315
312
|
|
|
316
313
|
|
|
317
314
|
def _normalized_subtree(value: str) -> str:
|
|
@@ -155,6 +155,7 @@ class RuleDocumentation:
|
|
|
155
155
|
rationale: str
|
|
156
156
|
remediation: str
|
|
157
157
|
category: RuleCategory
|
|
158
|
+
default_level: Severity = Severity.ERROR
|
|
158
159
|
autofix: AutofixPolicy = AutofixPolicy.NONE
|
|
159
160
|
aliases: tuple[str, ...] = ()
|
|
160
161
|
limitations: tuple[str, ...] = ()
|
|
@@ -207,6 +208,7 @@ class NativeRuleSpec:
|
|
|
207
208
|
rationale: str
|
|
208
209
|
remediation: str
|
|
209
210
|
category: RuleCategory
|
|
211
|
+
default_level: Severity
|
|
210
212
|
autofix: AutofixPolicy
|
|
211
213
|
aliases: tuple[str, ...]
|
|
212
214
|
limitations: tuple[str, ...]
|
|
@@ -283,6 +285,7 @@ class Rule(ABC):
|
|
|
283
285
|
rationale=authored.rationale,
|
|
284
286
|
remediation=authored.remediation,
|
|
285
287
|
category=authored.category,
|
|
288
|
+
default_level=authored.default_level,
|
|
286
289
|
autofix=authored.autofix,
|
|
287
290
|
aliases=authored.aliases,
|
|
288
291
|
limitations=authored.limitations,
|
|
@@ -264,6 +264,7 @@ class ComplexPostgresQueryRequiresArchitectureReview(Rule):
|
|
|
264
264
|
id: str = "complex-postgres-query-requires-architecture-review"
|
|
265
265
|
code: str = "SARJ437"
|
|
266
266
|
documentation = RuleDocumentation(
|
|
267
|
+
default_level=Severity.WARNING,
|
|
267
268
|
summary="Complex executable PostgreSQL query shapes require architecture review.",
|
|
268
269
|
rationale=(
|
|
269
270
|
"Join-heavy, deeply staged, or wide joined reads can obscure cardinality, bounds, ordering, and locking "
|
|
@@ -50,6 +50,7 @@ class FakesInSharedLocation(Rule):
|
|
|
50
50
|
id = "fakes-in-shared-location"
|
|
51
51
|
code = "SARJ428"
|
|
52
52
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
53
|
+
default_level=Severity.WARNING,
|
|
53
54
|
summary="Review named top-level test doubles for shared-support ownership unless they are intentionally scenario-local.",
|
|
54
55
|
rationale=(
|
|
55
56
|
"Reusable doubles hidden in an individual test module are difficult to discover and are often recreated. "
|
|
@@ -73,6 +73,7 @@ class FastapiExplicitOpenapiContract(Rule):
|
|
|
73
73
|
id: str = "fastapi-explicit-openapi-contract"
|
|
74
74
|
code: str = "SARJ094"
|
|
75
75
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
76
|
+
default_level=Severity.WARNING,
|
|
76
77
|
summary="Visible FastAPI operations pin locally reviewable metadata and avoid statically provable OpenAPI gaps.",
|
|
77
78
|
rationale=(
|
|
78
79
|
"FastAPI can infer valid schemas and default statuses. This stricter organizational policy pins locally "
|
|
@@ -32,6 +32,7 @@ class IacSourceCoupledTest(Rule):
|
|
|
32
32
|
id = "iac-source-coupled-test"
|
|
33
33
|
code = "SARJ412"
|
|
34
34
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
35
|
+
default_level=Severity.WARNING,
|
|
35
36
|
summary="Test uses raw Terraform/HCL text as an infrastructure-behavior oracle.",
|
|
36
37
|
rationale=(
|
|
37
38
|
"Substring and regex checks can pass on comments, formatting, or unreachable Terraform configuration "
|
{sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/mock_without_spec.py
RENAMED
|
@@ -121,6 +121,7 @@ class MockWithoutSpec(Rule):
|
|
|
121
121
|
id: str = "mock-without-spec"
|
|
122
122
|
code: str = "SARJ040"
|
|
123
123
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
124
|
+
default_level=Severity.WARNING,
|
|
124
125
|
summary="Unrestricted mock permits attributes outside the collaborator contract.",
|
|
125
126
|
rationale=(
|
|
126
127
|
"A mock without a spec permits removed or misspelled attributes; a callable mock without autospec may "
|
|
@@ -13,6 +13,7 @@ from sarj_python_lint.rule_base import (
|
|
|
13
13
|
RuleCategory,
|
|
14
14
|
RuleDocumentation,
|
|
15
15
|
RuleExample,
|
|
16
|
+
Severity,
|
|
16
17
|
is_suppressed,
|
|
17
18
|
parse_or_none,
|
|
18
19
|
)
|
|
@@ -42,6 +43,7 @@ class NamedRecordAtBoundaries(Rule):
|
|
|
42
43
|
id: str = "named-record-at-boundaries"
|
|
43
44
|
code: str = "SARJ008"
|
|
44
45
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
46
|
+
default_level=Severity.WARNING,
|
|
45
47
|
summary="Public Python API returns an unnamed fixed-shape record.",
|
|
46
48
|
rationale="A named record makes field types and required keys explicit to callers and static tooling.",
|
|
47
49
|
remediation="Define and return a `TypedDict`, Pydantic model, or frozen dataclass for the fixed record shape.",
|
|
@@ -204,6 +204,7 @@ class NegativeOnlyHttpStatusAssertion(Rule):
|
|
|
204
204
|
id = "negative-only-http-status-assertion"
|
|
205
205
|
code = "SARJ408"
|
|
206
206
|
documentation = RuleDocumentation(
|
|
207
|
+
default_level=Severity.WARNING,
|
|
207
208
|
summary="HTTP test assertion only excludes a server error instead of identifying the intended response.",
|
|
208
209
|
rationale=(
|
|
209
210
|
"Authentication, routing, validation, and domain failures can all replace the intended response while "
|
|
@@ -152,6 +152,7 @@ class NoAnalyticalAggregationInPostgresStore(Rule):
|
|
|
152
152
|
id: str = "no-analytical-aggregation-in-postgres-store"
|
|
153
153
|
code: str = "SARJ020"
|
|
154
154
|
documentation = RuleDocumentation(
|
|
155
|
+
default_level=Severity.WARNING,
|
|
155
156
|
summary="Potentially analytical PostgreSQL store queries require review.",
|
|
156
157
|
rationale=(
|
|
157
158
|
"Unbounded reporting and statistical scans can compete with transactional reads. "
|
|
@@ -13,6 +13,7 @@ from sarj_python_lint.rule_base import (
|
|
|
13
13
|
RuleCategory,
|
|
14
14
|
RuleDocumentation,
|
|
15
15
|
RuleExample,
|
|
16
|
+
Severity,
|
|
16
17
|
is_suppressed,
|
|
17
18
|
)
|
|
18
19
|
from sarj_python_lint.rules._annotation_semantics import AnnotationSemantics, scope_bound_names
|
|
@@ -37,6 +38,7 @@ class NoAnyMappingTypes(Rule):
|
|
|
37
38
|
id = "no-any-mapping-types"
|
|
38
39
|
code = "SARJ447"
|
|
39
40
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
41
|
+
default_level=Severity.WARNING,
|
|
40
42
|
summary="String-keyed mapping types must not erase their values with `Any`.",
|
|
41
43
|
rationale=(
|
|
42
44
|
"An `Any`-valued mapping disables checking transitively and conceals whether the value is a fixed record, "
|
|
@@ -13,6 +13,7 @@ from sarj_python_lint.rule_base import (
|
|
|
13
13
|
RuleCategory,
|
|
14
14
|
RuleDocumentation,
|
|
15
15
|
RuleExample,
|
|
16
|
+
Severity,
|
|
16
17
|
parse_or_none,
|
|
17
18
|
)
|
|
18
19
|
from sarj_python_lint.rules._paths import is_generated, is_test_path, is_test_support_path
|
|
@@ -30,6 +31,7 @@ class NoRawConnectionInTests(Rule):
|
|
|
30
31
|
id = "no-raw-connection-in-tests"
|
|
31
32
|
code = "SARJ429"
|
|
32
33
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
34
|
+
default_level=Severity.WARNING,
|
|
33
35
|
summary="Do not acquire raw database connections in tests.",
|
|
34
36
|
rationale=(
|
|
35
37
|
"Tests that reach through a pool couple assertions and setup to persistence internals, bypass the "
|
|
@@ -112,6 +112,7 @@ class NoRawSourceTextTestOracle(Rule):
|
|
|
112
112
|
id = "no-raw-source-text-test-oracle"
|
|
113
113
|
code = "SARJ402"
|
|
114
114
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
115
|
+
default_level=Severity.WARNING,
|
|
115
116
|
summary="Test uses raw text from a source-like project path as its oracle.",
|
|
116
117
|
rationale="Substring and regex checks can pass on comments or unreachable configuration and fail after behavior-preserving formatting changes.",
|
|
117
118
|
remediation=(
|
|
@@ -44,6 +44,7 @@ class NoRedundantLiteralDescription(Rule):
|
|
|
44
44
|
id = "no-restated-closed-domain-description"
|
|
45
45
|
code = "SARJ423"
|
|
46
46
|
documentation = RuleDocumentation(
|
|
47
|
+
default_level=Severity.WARNING,
|
|
47
48
|
summary="Do not restate a string Literal or local string Enum domain in its Pydantic description.",
|
|
48
49
|
rationale=(
|
|
49
50
|
"Pydantic already publishes literal and enum domains in JSON Schema; duplicate must-be prose can "
|
|
@@ -14,6 +14,7 @@ from sarj_python_lint.rule_base import (
|
|
|
14
14
|
RuleCategory,
|
|
15
15
|
RuleDocumentation,
|
|
16
16
|
RuleExample,
|
|
17
|
+
Severity,
|
|
17
18
|
parse_or_none,
|
|
18
19
|
)
|
|
19
20
|
from sarj_python_lint.rules._imports import ImportIndex
|
|
@@ -33,6 +34,7 @@ class NoRedundantModuleAliasExports(Rule):
|
|
|
33
34
|
id: str = "no-redundant-module-alias-exports"
|
|
34
35
|
code: str = "SARJ440"
|
|
35
36
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
37
|
+
default_level=Severity.WARNING,
|
|
36
38
|
summary="Do not manufacture public APIs from private names or replace the current module.",
|
|
37
39
|
rationale=(
|
|
38
40
|
"Binding a public name to a private implementation creates two names for one API and disguises the "
|
|
@@ -253,6 +253,7 @@ class NoRestatedComment(Rule):
|
|
|
253
253
|
id: str = "no-restated-comment"
|
|
254
254
|
code: str = "SARJ049"
|
|
255
255
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
256
|
+
default_level=Severity.WARNING,
|
|
256
257
|
summary="Short standalone comment lexically restates the immediately following simple action.",
|
|
257
258
|
rationale=(
|
|
258
259
|
"When a comment adds no rationale, scope, ordering, or constraint, it duplicates code and can become stale. "
|
|
@@ -28,6 +28,7 @@ class NoTypedDocSections(Rule):
|
|
|
28
28
|
id = "no-docstring-type-restatement"
|
|
29
29
|
code = "SARJ092"
|
|
30
30
|
documentation = RuleDocumentation(
|
|
31
|
+
default_level=Severity.WARNING,
|
|
31
32
|
summary="A docstring type label repeats an annotation from the fully typed signature.",
|
|
32
33
|
rationale=(
|
|
33
34
|
"A repeated type spelling can drift from the annotation and obscures the behavioral contract that only prose "
|
|
@@ -29,6 +29,7 @@ class NoUnusedValueMarker(Rule):
|
|
|
29
29
|
id = "no-unused-value-marker"
|
|
30
30
|
code = "SARJ452"
|
|
31
31
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
32
|
+
default_level=Severity.WARNING,
|
|
32
33
|
summary="Do not use standalone assignments to `_` to discard values.",
|
|
33
34
|
rationale=(
|
|
34
35
|
"A standalone `_ = value` assignment adds a binding without clarifying intent. A side-effecting call can "
|
|
@@ -114,6 +114,7 @@ class NoWholeRequestResponsePayloadInLog(Rule):
|
|
|
114
114
|
id: str = "no-whole-request-response-payload-in-log"
|
|
115
115
|
code: str = "SARJ436"
|
|
116
116
|
documentation = RuleDocumentation(
|
|
117
|
+
default_level=Severity.WARNING,
|
|
117
118
|
summary="Whole request or response payloads passed to logging calls require review.",
|
|
118
119
|
rationale=(
|
|
119
120
|
"Request and response bodies often contain personal, financial, or echoed authentication data, while "
|
|
@@ -56,6 +56,7 @@ class OpaqueParametrizeCaseNeedsId(Rule):
|
|
|
56
56
|
id: str = "opaque-parametrize-case-needs-id"
|
|
57
57
|
code: str = "SARJ042"
|
|
58
58
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
59
|
+
default_level=Severity.WARNING,
|
|
59
60
|
summary="Opaque static pytest parameter cases rely on argument-name-and-index fallback IDs.",
|
|
60
61
|
rationale="Fallback IDs such as `payload0` are hard to diagnose and silently change when the table is reordered.",
|
|
61
62
|
remediation=(
|
{sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/over_mocked_test.py
RENAMED
|
@@ -179,6 +179,7 @@ class OverMockedTest(Rule):
|
|
|
179
179
|
id: str = "over-mocked-test"
|
|
180
180
|
code: str = "SARJ062"
|
|
181
181
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
182
|
+
default_level=Severity.WARNING,
|
|
182
183
|
summary="Tests should not use more than five independently rooted test doubles or collaborator substitutions.",
|
|
183
184
|
rationale="Broad double setup obscures the behavior under test and often couples tests to implementation wiring.",
|
|
184
185
|
remediation=(
|
|
@@ -18,6 +18,7 @@ from sarj_python_lint.rule_base import (
|
|
|
18
18
|
RuleCategory,
|
|
19
19
|
RuleDocumentation,
|
|
20
20
|
RuleExample,
|
|
21
|
+
Severity,
|
|
21
22
|
is_suppressed,
|
|
22
23
|
parse_or_none,
|
|
23
24
|
)
|
|
@@ -77,6 +78,7 @@ class PreferCollectionComprehension(Rule):
|
|
|
77
78
|
id = "prefer-collection-comprehension"
|
|
78
79
|
code = "SARJ430"
|
|
79
80
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
81
|
+
default_level=Severity.WARNING,
|
|
80
82
|
summary="Single-purpose fresh collection builder loop — prefer a direct comprehension.",
|
|
81
83
|
rationale=(
|
|
82
84
|
"An empty collection followed by a loop whose only behavior is one projection or filtered insertion "
|
|
@@ -94,6 +94,7 @@ class PreferConstantTimeSecretCompare(Rule):
|
|
|
94
94
|
id: str = "prefer-constant-time-secret-compare"
|
|
95
95
|
code: str = "SARJ011"
|
|
96
96
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
97
|
+
default_level=Severity.WARNING,
|
|
97
98
|
summary="Externally supplied authenticators are compared with timing-sensitive equality.",
|
|
98
99
|
rationale=(
|
|
99
100
|
"Ordinary equality may short-circuit based on matching content when attacker-controlled credentials are "
|
|
@@ -120,6 +120,7 @@ class PreferFstringOverConcat(Rule):
|
|
|
120
120
|
id: str = "prefer-fstring-over-concat"
|
|
121
121
|
code: str = "SARJ068"
|
|
122
122
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
123
|
+
default_level=Severity.WARNING,
|
|
123
124
|
summary="Prefer f-strings for short human-readable interpolation when they make the result clearer.",
|
|
124
125
|
rationale="For prose-like strings, f-strings keep interpolated values and surrounding text visible together.",
|
|
125
126
|
remediation=(
|
|
@@ -73,6 +73,7 @@ class PreferImmutableModuleConstant(Rule):
|
|
|
73
73
|
id: str = "prefer-immutable-module-constant"
|
|
74
74
|
code: str = "SARJ096"
|
|
75
75
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
76
|
+
default_level=Severity.WARNING,
|
|
76
77
|
summary=("Nonempty uppercase module collections allow top-level membership or keys to change at runtime."),
|
|
77
78
|
rationale=(
|
|
78
79
|
"A constant-looking collection can expose process-wide top-level mutation even when callers intend it as a "
|
|
@@ -37,6 +37,7 @@ class PreferInjectedDependencyOverMonkeypatch(Rule):
|
|
|
37
37
|
id: str = "prefer-injected-dependency-over-monkeypatch"
|
|
38
38
|
code: str = "SARJ445"
|
|
39
39
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
40
|
+
default_level=Severity.WARNING,
|
|
40
41
|
summary="Tests should inject dependencies instead of replacing attributes through ambient patching.",
|
|
41
42
|
rationale=(
|
|
42
43
|
"Attribute patching hides collaborators and configuration behind ambient module or object state, coupling "
|
|
@@ -341,6 +341,7 @@ class PreferLibraryFake(Rule):
|
|
|
341
341
|
id: str = "prefer-library-fake"
|
|
342
342
|
code: str = "SARJ059"
|
|
343
343
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
344
|
+
default_level=Severity.WARNING,
|
|
344
345
|
summary="Prefer a maintained fake, emulator, recorder, or test service for substantial third-party protocols.",
|
|
345
346
|
rationale=(
|
|
346
347
|
"A substantial hand-written protocol model can drift from supported request, state, and error behavior."
|
|
@@ -86,6 +86,7 @@ class PreferMatchExceptionDispatch(Rule):
|
|
|
86
86
|
id: str = "prefer-match-exception-dispatch"
|
|
87
87
|
code: str = "SARJ453"
|
|
88
88
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
89
|
+
default_level=Severity.WARNING,
|
|
89
90
|
summary="Prefer guarded match/case for refined exception type dispatch.",
|
|
90
91
|
rationale=(
|
|
91
92
|
"A long exception classifier that repeats isinstance checks and then refines one exception type hides "
|
|
@@ -38,6 +38,7 @@ class PreferMatchValueDispatch(Rule):
|
|
|
38
38
|
id: str = "prefer-match-value-dispatch"
|
|
39
39
|
code: str = "SARJ439"
|
|
40
40
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
41
|
+
default_level=Severity.WARNING,
|
|
41
42
|
summary="Prefer match/case for repeated dispatch on one value with a fallback.",
|
|
42
43
|
rationale="A single dispatch subject makes distinct value cases and their fallback easier to review.",
|
|
43
44
|
remediation=(
|
|
@@ -96,6 +96,7 @@ class PreferModuleLevelConstant(Rule):
|
|
|
96
96
|
id: str = "prefer-module-level-constant"
|
|
97
97
|
code: str = "SARJ039"
|
|
98
98
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
99
|
+
default_level=Severity.WARNING,
|
|
99
100
|
summary="Hoist repeatedly read static values when an immutable module representation preserves behavior.",
|
|
100
101
|
rationale=(
|
|
101
102
|
"Rebuilding a substantial static collection repeats allocation, while calling `re.compile` with a "
|
|
@@ -44,6 +44,7 @@ class PreferMonkeypatchForProcessStateInTest(Rule):
|
|
|
44
44
|
id = "prefer-monkeypatch-for-process-state-in-test"
|
|
45
45
|
code = "SARJ446"
|
|
46
46
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
47
|
+
default_level=Severity.WARNING,
|
|
47
48
|
summary="Test mutates process-wide state without a restoring test scope.",
|
|
48
49
|
rationale=(
|
|
49
50
|
"The working directory and Python import registries are shared by every test in the process. A direct "
|
|
@@ -40,6 +40,7 @@ class PreferNonNullableCollection(Rule):
|
|
|
40
40
|
id: str = "prefer-non-nullable-collection"
|
|
41
41
|
code: str = "SARJ082"
|
|
42
42
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
43
|
+
default_level=Severity.WARNING,
|
|
43
44
|
summary="Avoid nullable list parameters that are immediately collapsed to an empty list.",
|
|
44
45
|
rationale=(
|
|
45
46
|
"When an implementation immediately replaces both `None` and an empty list with the same fresh empty list, "
|
{sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_or_pattern.py
RENAMED
|
@@ -39,6 +39,7 @@ class PreferOrPattern(Rule):
|
|
|
39
39
|
id: str = "prefer-or-pattern"
|
|
40
40
|
code: str = "SARJ070"
|
|
41
41
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
42
|
+
default_level=Severity.WARNING,
|
|
42
43
|
summary="Merge adjacent `case` arms with identical bodies into one or-pattern.",
|
|
43
44
|
rationale="An or-pattern expresses shared handling once and prevents identical arms from drifting apart.",
|
|
44
45
|
remediation="Join the equivalent patterns with `|` and keep their shared body under the merged arm.",
|
|
@@ -19,6 +19,7 @@ from sarj_python_lint.rule_base import (
|
|
|
19
19
|
RuleCategory,
|
|
20
20
|
RuleDocumentation,
|
|
21
21
|
RuleExample,
|
|
22
|
+
Severity,
|
|
22
23
|
is_suppressed,
|
|
23
24
|
parse_or_none,
|
|
24
25
|
)
|
|
@@ -52,6 +53,7 @@ class PreferPydanticJsonValue(Rule):
|
|
|
52
53
|
id = "prefer-pydantic-json-value"
|
|
53
54
|
code = "SARJ454"
|
|
54
55
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
56
|
+
default_level=Severity.WARNING,
|
|
55
57
|
summary="Recursive JSON value alias duplicates `pydantic.JsonValue`.",
|
|
56
58
|
rationale=(
|
|
57
59
|
"Pydantic's canonical JSON value alias keeps the static contract aligned with runtime validation and "
|
|
@@ -114,6 +114,7 @@ class PreferSelfTypeAnnotation(Rule):
|
|
|
114
114
|
id: str = "prefer-self-type-annotation"
|
|
115
115
|
code: str = "SARJ078"
|
|
116
116
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
117
|
+
default_level=Severity.WARNING,
|
|
117
118
|
summary="Prefer `Self` for self-returning methods and alternate constructors.",
|
|
118
119
|
rationale="`Self` preserves the concrete subclass type when an inherited method returns its receiver or constructs through its class receiver.",
|
|
119
120
|
remediation="Import `Self` from `typing` (or `typing_extensions` on Python before 3.11) and use it as the return annotation.",
|
|
@@ -13,6 +13,7 @@ from sarj_python_lint.rule_base import (
|
|
|
13
13
|
RuleCategory,
|
|
14
14
|
RuleDocumentation,
|
|
15
15
|
RuleExample,
|
|
16
|
+
Severity,
|
|
16
17
|
is_suppressed,
|
|
17
18
|
parse_or_none,
|
|
18
19
|
)
|
|
@@ -46,6 +47,7 @@ class PreferSetIsdisjoint(Rule):
|
|
|
46
47
|
id = "prefer-set-isdisjoint"
|
|
47
48
|
code = "SARJ431"
|
|
48
49
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
50
|
+
default_level=Severity.WARNING,
|
|
49
51
|
summary="Prefer `set.isdisjoint` when a built-in set intersection is used only as a boolean predicate.",
|
|
50
52
|
rationale="`isdisjoint` names the overlap predicate directly and avoids allocating an intersection that is immediately discarded.",
|
|
51
53
|
remediation="Use `left.isdisjoint(right)` and negate it when the condition requires overlap.",
|
|
@@ -42,6 +42,7 @@ class PreferWalrusAwaitedNoneGuard(Rule):
|
|
|
42
42
|
id = "prefer-walrus-awaited-none-guard"
|
|
43
43
|
code = "SARJ432"
|
|
44
44
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
45
|
+
default_level=Severity.WARNING,
|
|
45
46
|
summary="Bind a compact awaited lookup in its immediately following terminal None guard.",
|
|
46
47
|
rationale=(
|
|
47
48
|
"When an awaited lookup and its terminal None guard are adjacent, binding in the condition keeps "
|
|
@@ -13,6 +13,7 @@ from sarj_python_lint.rule_base import (
|
|
|
13
13
|
RuleCategory,
|
|
14
14
|
RuleDocumentation,
|
|
15
15
|
RuleExample,
|
|
16
|
+
Severity,
|
|
16
17
|
is_suppressed,
|
|
17
18
|
parse_or_none,
|
|
18
19
|
)
|
|
@@ -199,6 +200,7 @@ class PreferWalrusComprehensionFilter(Rule):
|
|
|
199
200
|
id: str = "prefer-walrus-comprehension-filter"
|
|
200
201
|
code: str = "SARJ076"
|
|
201
202
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
203
|
+
default_level=Severity.WARNING,
|
|
202
204
|
summary="The same call runs in a comprehension filter and its result.",
|
|
203
205
|
rationale="When both evaluations are intended to produce one stable value, repeating the call wastes work and obscures that relationship.",
|
|
204
206
|
remediation=(
|
|
@@ -14,6 +14,7 @@ from sarj_python_lint.rule_base import (
|
|
|
14
14
|
RuleCategory,
|
|
15
15
|
RuleDocumentation,
|
|
16
16
|
RuleExample,
|
|
17
|
+
Severity,
|
|
17
18
|
is_suppressed,
|
|
18
19
|
parse_or_none,
|
|
19
20
|
)
|
|
@@ -58,6 +59,7 @@ class PreferWalrusRegexMatch(Rule):
|
|
|
58
59
|
id: str = "prefer-walrus-regex-match"
|
|
59
60
|
code: str = "SARJ081"
|
|
60
61
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
62
|
+
default_level=Severity.WARNING,
|
|
61
63
|
summary="A proven regex Match-or-None result is assigned only for the following condition.",
|
|
62
64
|
rationale="A named expression can keep a short regex operation with its only condition while preserving access to the result.",
|
|
63
65
|
remediation=(
|
|
@@ -14,6 +14,7 @@ from sarj_python_lint.rule_base import (
|
|
|
14
14
|
RuleCategory,
|
|
15
15
|
RuleDocumentation,
|
|
16
16
|
RuleExample,
|
|
17
|
+
Severity,
|
|
17
18
|
is_suppressed,
|
|
18
19
|
parse_or_none,
|
|
19
20
|
)
|
|
@@ -30,6 +31,7 @@ class PreferWalrusStreamLoop(Rule):
|
|
|
30
31
|
id: str = "prefer-walrus-stream-loop"
|
|
31
32
|
code: str = "SARJ077"
|
|
32
33
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
34
|
+
default_level=Severity.WARNING,
|
|
33
35
|
summary="Collapse a compact producer assignment and immediate sentinel break into a named-expression loop.",
|
|
34
36
|
rationale="A named-expression loop can state a repeated producer call and its termination condition together.",
|
|
35
37
|
remediation=(
|
|
@@ -45,6 +45,7 @@ class PytestFixtureReturnsBareTuple(Rule):
|
|
|
45
45
|
id: str = "pytest-fixture-returns-bare-tuple"
|
|
46
46
|
code: str = "SARJ044"
|
|
47
47
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
48
|
+
default_level=Severity.WARNING,
|
|
48
49
|
summary="Pytest fixture exposes a fixed positional record as an unnamed tuple.",
|
|
49
50
|
rationale=(
|
|
50
51
|
"Tuple-shaped fixture APIs encode each value's role in its position, so call sites are opaque and "
|
|
@@ -46,6 +46,7 @@ class RedundantDocstring(Rule):
|
|
|
46
46
|
id: str = "redundant-docstring"
|
|
47
47
|
code: str = "SARJ050"
|
|
48
48
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
49
|
+
default_level=Severity.WARNING,
|
|
49
50
|
summary="Function or plain-method docstring only repeats its declaration.",
|
|
50
51
|
rationale="Restating a clear name and signature creates maintenance work without helping callers.",
|
|
51
52
|
remediation=(
|
|
@@ -61,6 +61,7 @@ class RepeatedKwargHeavyCallInTest(Rule):
|
|
|
61
61
|
id: str = "repeated-kwarg-heavy-call-in-test"
|
|
62
62
|
code: str = "SARJ045"
|
|
63
63
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
64
|
+
default_level=Severity.WARNING,
|
|
64
65
|
summary="Tests repeat at least seven explicit keyword names across calls to the same callee.",
|
|
65
66
|
rationale=(
|
|
66
67
|
"Large repeated argument lists duplicate incidental setup, bury scenario differences, and make signature "
|
|
@@ -80,6 +80,7 @@ class RepeatedStaticCallCases(Rule):
|
|
|
80
80
|
id = "repeated-static-call-cases"
|
|
81
81
|
code = "SARJ413"
|
|
82
82
|
documentation = RuleDocumentation(
|
|
83
|
+
default_level=Severity.WARNING,
|
|
83
84
|
summary="Three same-shape literal call assertions may be independent parameter cases.",
|
|
84
85
|
rationale=(
|
|
85
86
|
"When the calls are independent, named parameters isolate failures and identify the input that failed. "
|
|
@@ -118,6 +118,7 @@ class RequireKeywordOnlySwapProneParams(Rule):
|
|
|
118
118
|
id: str = "require-keyword-only-swap-prone-params"
|
|
119
119
|
code: str = "SARJ034"
|
|
120
120
|
documentation = RuleDocumentation(
|
|
121
|
+
default_level=Severity.WARNING,
|
|
121
122
|
summary="Risky-name positional parameters sharing a primitive annotation may be confused.",
|
|
122
123
|
rationale="A caller can exchange semantically distinct positional values without a type-checking failure.",
|
|
123
124
|
remediation=(
|
|
@@ -194,6 +194,7 @@ class RequirePortForService(ProjectRule):
|
|
|
194
194
|
id: str = "require-port-for-service"
|
|
195
195
|
code: str = "SARJ071"
|
|
196
196
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
197
|
+
default_level=Severity.WARNING,
|
|
197
198
|
summary="Consider a consumer-owned port when visible service structure suggests a substitution boundary.",
|
|
198
199
|
rationale="A small port can decouple consumers when they genuinely need to substitute a concrete service boundary.",
|
|
199
200
|
remediation=(
|
|
@@ -97,6 +97,7 @@ class RequirePydanticForExternalJson(Rule):
|
|
|
97
97
|
id = "require-pydantic-for-external-json"
|
|
98
98
|
code = "SARJ411"
|
|
99
99
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
100
|
+
default_level=Severity.WARNING,
|
|
100
101
|
summary="Proven external JSON record fields are consumed before runtime schema validation.",
|
|
101
102
|
rationale=(
|
|
102
103
|
"Annotations, casts, and partial key checks do not validate a wire protocol; a maintained runtime "
|
|
@@ -95,6 +95,7 @@ class RequirePydanticOrdinalLowerBound(Rule):
|
|
|
95
95
|
id = "require-pydantic-ordinal-lower-bound"
|
|
96
96
|
code = "SARJ418"
|
|
97
97
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
98
|
+
default_level=Severity.WARNING,
|
|
98
99
|
summary="A Pydantic ordinal field maps its first position to N but accepts smaller integers.",
|
|
99
100
|
rationale=(
|
|
100
101
|
"An unqualified `N for the first ...` mapping defines the origin of an ordinal field; matching schema "
|
|
@@ -95,6 +95,7 @@ class StoreGetDelegatesToBulkRead(Rule):
|
|
|
95
95
|
id = "store-get-delegates-to-bulk-read"
|
|
96
96
|
code = "SARJ421"
|
|
97
97
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
98
|
+
default_level=Severity.WARNING,
|
|
98
99
|
summary="A store singleton operation should reuse its equivalent bulk implementation.",
|
|
99
100
|
rationale=(
|
|
100
101
|
"Independent singleton and bulk queries can drift in filtering, mutation semantics, row conversion, "
|
|
@@ -65,6 +65,7 @@ class StoreInsertRequiresOnConflict(Rule):
|
|
|
65
65
|
id: str = "replay-contract-insert-requires-duplicate-policy"
|
|
66
66
|
code: str = "SARJ018"
|
|
67
67
|
documentation = RuleDocumentation(
|
|
68
|
+
default_level=Severity.WARNING,
|
|
68
69
|
summary="A literal INSERT in a replay-named store callable must declare duplicate behavior.",
|
|
69
70
|
rationale=(
|
|
70
71
|
"A store callable named ensure, enqueue, record_once, get_or_create, create_if_absent, or "
|
|
@@ -56,6 +56,7 @@ class TimestampOrderRequiresTiebreaker(Rule):
|
|
|
56
56
|
id = "timestamp-order-requires-tiebreaker"
|
|
57
57
|
code = "SARJ407"
|
|
58
58
|
documentation = RuleDocumentation(
|
|
59
|
+
default_level=Severity.WARNING,
|
|
59
60
|
summary=(
|
|
60
61
|
"Bounded store SQL whose final result-order key looks like a `*_at` timestamp should include a "
|
|
61
62
|
"deterministic secondary key."
|
|
@@ -32,6 +32,7 @@ class TypedErrorReasons(Rule):
|
|
|
32
32
|
id = "typed-error-reasons"
|
|
33
33
|
code = "SARJ435"
|
|
34
34
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
35
|
+
default_level=Severity.WARNING,
|
|
35
36
|
summary="Review joined exception strings for fixed reason identities versus dynamic context.",
|
|
36
37
|
rationale=(
|
|
37
38
|
"Fixed reason identities benefit from stable codes for API clients, UI formatting, telemetry, and "
|
|
@@ -35,6 +35,7 @@ class UnusedTestFactoryOption(Rule):
|
|
|
35
35
|
id = "unused-test-factory-option"
|
|
36
36
|
code = "SARJ443"
|
|
37
37
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
38
|
+
default_level=Severity.WARNING,
|
|
38
39
|
summary="A private test factory exposes a literal option that visible callers never vary.",
|
|
39
40
|
rationale="Unused customization obscures the values that actually distinguish test scenarios.",
|
|
40
41
|
remediation="Keep the value in the factory's construction instead of exposing an unused option; retain it if external callers need it.",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/_analysis_session.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_ast_index.py
RENAMED
|
File without changes
|
{sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_ast_position.py
RENAMED
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_docstrings.py
RENAMED
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_first_party.py
RENAMED
|
File without changes
|
{sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_fixed_record.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_project_index.py
RENAMED
|
File without changes
|
{sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_prose_budget.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_test_assertions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_comment_cruft.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_dunder_all.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_secret_in_log.py
RENAMED
|
File without changes
|
{sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_select_star.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_class_row.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_str_enum.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.87.2 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/unused_mock_setup.py
RENAMED
|
File without changes
|