sarj-python-lint 0.87.3__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.
Files changed (143) hide show
  1. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/PKG-INFO +1 -1
  2. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/pyproject.toml +1 -1
  3. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/__main__.py +6 -11
  4. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/_ratchet_cli.py +2 -2
  5. sarj_python_lint-0.87.4/src/sarj_python_lint/json_boundary.py +10 -0
  6. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/ratchet.py +6 -9
  7. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/.gitignore +0 -0
  8. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/LICENSE +0 -0
  9. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/README.md +0 -0
  10. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/__init__.py +0 -0
  11. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/_analysis_session.py +0 -0
  12. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/_filesystem.py +0 -0
  13. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/_python_target.py +0 -0
  14. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/_secret_names.py +0 -0
  15. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/_version.py +0 -0
  16. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/py.typed +0 -0
  17. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rule_base.py +0 -0
  18. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/__init__.py +0 -0
  19. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
  20. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_ast_index.py +0 -0
  21. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_ast_position.py +0 -0
  22. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_comments.py +0 -0
  23. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_docstrings.py +0 -0
  24. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_fastapi.py +0 -0
  25. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_first_party.py +0 -0
  26. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
  27. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_imports.py +0 -0
  28. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_logging.py +0 -0
  29. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_paths.py +0 -0
  30. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_project_index.py +0 -0
  31. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
  32. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_pytest.py +0 -0
  33. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_registry.py +0 -0
  34. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_sql.py +0 -0
  35. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
  36. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
  37. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
  38. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
  39. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
  40. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
  41. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
  42. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
  43. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
  44. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
  45. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
  46. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
  47. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
  48. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
  49. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
  50. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
  51. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
  52. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
  53. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
  54. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
  55. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
  56. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
  57. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
  58. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
  59. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
  60. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
  61. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
  62. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
  63. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
  64. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
  65. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
  66. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
  67. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
  68. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
  69. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
  70. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
  71. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
  72. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
  73. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
  74. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
  75. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
  76. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
  77. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
  78. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
  79. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
  80. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_select_star.py +0 -0
  81. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
  82. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
  83. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
  84. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
  85. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
  86. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
  87. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
  88. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
  89. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
  90. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
  91. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
  92. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
  93. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
  94. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
  95. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
  96. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
  97. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
  98. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
  99. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
  100. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
  101. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
  102. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
  103. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
  104. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
  105. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
  106. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
  107. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
  108. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
  109. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
  110. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
  111. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
  112. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
  113. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
  114. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
  115. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
  116. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
  117. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
  118. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
  119. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
  120. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
  121. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
  122. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
  123. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
  124. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
  125. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
  126. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
  127. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
  128. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
  129. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
  130. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
  131. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
  132. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
  133. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/require_typed_http_test_response.py +0 -0
  134. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
  135. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/stepdown.py +0 -0
  136. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
  137. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
  138. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
  139. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
  140. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
  141. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
  142. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
  143. {sarj_python_lint-0.87.3 → sarj_python_lint-0.87.4}/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: 0.87.3
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/
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sarj-python-lint"
3
- version = "0.87.3"
3
+ version = "0.87.4"
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" }]
@@ -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: object = json.loads( # pyright: ignore[reportAny] — json.loads is an untyped stdlib boundary; the shape is narrowed below
339
- path.read_text(encoding="utf-8")
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(): # pyright: ignore[reportUnknownVariableType] — json.loads yields Any leaves
345
- if not isinstance(file_key, str) or not isinstance(per_code, dict):
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: object = json.loads(completed.stdout) # pyright: ignore[reportAny] -- validated below
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: object = json.loads( # pyright: ignore[reportAny] — json.loads is an untyped stdlib boundary; every read below narrows
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 isinstance(mapping, dict):
241
+ if not is_object_mapping(mapping):
242
242
  return None
243
- return mapping.get(key) # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType] — json leaves are Any
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 isinstance(value, dict) and all(
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: