sarj-python-lint 1.101.0__tar.gz → 1.101.10__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-1.101.0 → sarj_python_lint-1.101.10}/PKG-INFO +1 -1
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/pyproject.toml +1 -1
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_opaque_contracts.py +12 -5
- sarj_python_lint-1.101.10/src/sarj_python_lint/rules/_postgres_ctas.py +191 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_transactional_sql.py +16 -6
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +39 -3
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_precise_object_contract.py +5 -2
- sarj_python_lint-1.101.10/src/sarj_python_lint/rules/prefer_typed_mapping_get.py +378 -0
- sarj_python_lint-1.101.0/src/sarj_python_lint/rules/prefer_typed_mapping_get.py +0 -189
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/.gitignore +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/LICENSE +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/README.md +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/__init__.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/__main__.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_analysis_session.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_aliases.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_annotations.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_comments.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_declared_contracts.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_declared_tests.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_docs.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_enums.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_exhaustiveness.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_inert.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_parameters.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_repeated.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_security.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_sql_projection.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_autofix_tests.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_file_context.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_filesystem.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_fixes.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_parallel.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_prepared_sources.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_python_target.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_ratchet_cli.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_rule_descriptors.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_secret_names.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_source.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/_version.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/application_logging.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/autofix.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/benchmark.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/cast_access.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/interpreter_argv.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/json_boundary.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/py.typed +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/ratchet.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rule_base.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rule_metadata.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/__init__.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_annotation_origins.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_ast_index.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_ast_names.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_ast_position.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_async_lifecycle.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_binding_inventory.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_closed_helpers.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_comment_narration.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_comments.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_copy_on_write.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_data_union_discriminator.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_declared_contracts.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_docstrings.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_exports.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_fastapi.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_first_party.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_imports.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_inert_model_annotation.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_inherited_contract.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_local_alias_fix.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_local_source.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_logging.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_mapping_shape_callbacks.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_namespace_access.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_native_namespace_capability.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_native_object_contracts.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_numeric_proof.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_paths.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_postgres.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_project_index.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_pydantic_field_contract.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_pytest.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_registry.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_resolved_operation_signature.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_route_shapes.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_runtime_bindings.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_runtime_registry.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_service_http_callbacks.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_set_fields.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_sql.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_sql_aggregate_identity.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_sql_explain.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_sql_policy_source.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_static_json_alias.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_store_sql.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_store_writes.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_test_composition.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_test_provenance.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/_type_guard_symbols.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/async_executor_shutdown.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/async_subprocess_cancellation_cleanup.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/cancel_owned_task_without_join.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/delete_route_returns_no_content.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/duplicate_adjacent_exception_handler.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/duplicate_closed_pure_helper.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/duplicate_pytest_fixture_params.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/failed_probe_zero_threshold.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/nan_hidden_by_builtin_min.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_async_client_in_constructor.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_async_function_cache.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_before_validator_input_mutation.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_blanket_suppression.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_broad_keyword_capture.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_conflicting_pydantic_alias_validation.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_contradictory_type_guard.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_create_verb_in_post_path.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_custom_control_flow_exception.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_defaulted_environment_setting.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_discarded_tagged_outcome.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_discarded_validation_result.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_dual_shape_model_field_reader.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_duplicate_field_validator_body.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_exception_text_in_500_detail.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_fixed_sleep_in_loop.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_folded_bad_request_not_found.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_generic_json_parser.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_hasattr.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_impossible_pydantic_field_bounds.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_input_model_mutation.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_interpreter_source_arguments.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_invalid_pydantic_bypass.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_invalid_pydantic_validator_return.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_loguru_exc_info.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_loguru_printf_format.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_mocked_pydantic_value_object.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_mutating_container_transform.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_mutating_input_with_result.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_partial_type_is.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_recording_store.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_redundant_attribute_unpacking.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_redundant_local_alias.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_redundant_sql_alias.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_select_star.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_shallow_record_type_guard.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_slash_collection_root_under_prefix.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_test_comments.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_test_method_grafting.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_unknown_pydantic_validator_field.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_unused_copy_result.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/no_work_verb_get_route.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_application_model_joins.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_bulk_upsert.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_declarative_batch_validation.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_direct_import_module.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_discriminated_model_union.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_grouped_settings.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_native_string_check.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_optional_composite.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_psycopg_executemany.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_pydantic_model_assertion.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_pytest_dependency_fixtures.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_pytest_fixture_contract.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_required_constructor_parameters.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_runtime_validation.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_typed_cli.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_typed_settings_field.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/pytest_fixture_returns_closed_resource.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/redundant_test_constructor_forwarder.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/repeated_unimplemented_test_contract.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_constrained_api_integer.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_exp_on_jwt_decode.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_injectable_retry_sleep.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_precise_factory_signature.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_pydantic_for_mapping_shape.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/service_singleton_delegates_to_bulk.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/stepdown.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/store_field_update_reuses_upsert.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/store_insert_requires_explicit_conflict_policy.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/store_mutation_command_fanout.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/test_without_explicit_oracle.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/rules/unused_test_factory_option.py +0 -0
- {sarj_python_lint-1.101.0 → sarj_python_lint-1.101.10}/src/sarj_python_lint/suppression_policy.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sarj-python-lint
|
|
3
|
-
Version: 1.101.
|
|
3
|
+
Version: 1.101.10
|
|
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/
|
|
@@ -16,6 +16,7 @@ if TYPE_CHECKING:
|
|
|
16
16
|
from pathlib import Path
|
|
17
17
|
|
|
18
18
|
from sarj_python_lint._file_context import PythonFileContext
|
|
19
|
+
from sarj_python_lint.rules._local_source import LocalSourceFacts
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
type _Function = ast.FunctionDef | ast.AsyncFunctionDef
|
|
@@ -111,11 +112,13 @@ class OpaqueContractFacts:
|
|
|
111
112
|
context: PythonFileContext,
|
|
112
113
|
facts: MappingShapeFacts,
|
|
113
114
|
*,
|
|
115
|
+
local_source: LocalSourceFacts,
|
|
114
116
|
modules: dict[Path, OpaqueContractFacts] | None = None,
|
|
115
117
|
budget: _ProofBudget | None = None,
|
|
116
118
|
) -> None:
|
|
117
119
|
self.context = context
|
|
118
120
|
self.facts = facts
|
|
121
|
+
self.local_source = local_source
|
|
119
122
|
self.native = NativeObjectContracts(context, facts)
|
|
120
123
|
self.guards: dict[str, _Refinement | None] = {}
|
|
121
124
|
self.checked: dict[_Function, frozenset[ast.arg]] = {}
|
|
@@ -712,20 +715,24 @@ class OpaqueContractFacts:
|
|
|
712
715
|
|
|
713
716
|
def _imported_source(self, qualified: str) -> tuple[OpaqueContractFacts, ast.FunctionDef] | None:
|
|
714
717
|
module, _, name = qualified.rpartition(".")
|
|
715
|
-
path = self.context.session.
|
|
716
|
-
self.context.path, module, 0, facts=self.context.session.first_party
|
|
717
|
-
)
|
|
718
|
+
path = self.local_source.resolve_module(self.context.path, module, 0, facts=self.context.session.first_party)
|
|
718
719
|
if path is not None and (owner := self.modules.get(path.resolve())) is not None:
|
|
719
720
|
return owner.export(name)
|
|
720
721
|
if len(self.modules) >= _MAX_GUARDS:
|
|
721
722
|
return None
|
|
722
|
-
loaded = self.
|
|
723
|
+
loaded = self.local_source.read_module(path) if path is not None else None
|
|
723
724
|
if loaded is None:
|
|
724
725
|
return None
|
|
725
726
|
from sarj_python_lint._file_context import PythonFileContext # ruff: ignore[import-outside-top-level] -- source loading runs after AnalysisSession initialization.
|
|
726
727
|
|
|
727
728
|
context = PythonFileContext(loaded.path, loaded.source, self.context.session)
|
|
728
|
-
owner = OpaqueContractFacts(
|
|
729
|
+
owner = OpaqueContractFacts(
|
|
730
|
+
context,
|
|
731
|
+
MappingShapeFacts(context),
|
|
732
|
+
local_source=self.local_source,
|
|
733
|
+
modules=self.modules,
|
|
734
|
+
budget=self.budget,
|
|
735
|
+
)
|
|
729
736
|
return owner.export(name)
|
|
730
737
|
|
|
731
738
|
def export(self, name: str) -> tuple[OpaqueContractFacts, ast.FunctionDef] | None:
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
import sqlglot
|
|
7
|
+
from sqlglot import exp
|
|
8
|
+
from sqlglot.errors import SqlglotError
|
|
9
|
+
from sqlglot.tokenizer_core import TokenType
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from collections.abc import Sequence
|
|
14
|
+
|
|
15
|
+
from sqlglot.tokenizer_core import Token
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
_COPY_END = re.compile(r"(?m)^\\\.(?:\r?$)")
|
|
19
|
+
_TEMP_TABLE = (TokenType.CREATE, TokenType.TEMPORARY, TokenType.TABLE)
|
|
20
|
+
_ON_COMMIT_DROP = (TokenType.ON, TokenType.COMMIT, TokenType.DROP)
|
|
21
|
+
_ON_COMMIT_ROWS_SIZE = 4
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def normalize_postgres_ctas(source: str) -> str:
|
|
25
|
+
source = _mask_copy_input(source)
|
|
26
|
+
try:
|
|
27
|
+
tokens = sqlglot.tokenize(source, read="postgres")
|
|
28
|
+
except SqlglotError, RecursionError:
|
|
29
|
+
return source
|
|
30
|
+
output = list(source)
|
|
31
|
+
statement: list[Token] = []
|
|
32
|
+
for token in tokens:
|
|
33
|
+
if token.token_type is not TokenType.SEMICOLON:
|
|
34
|
+
statement.append(token)
|
|
35
|
+
continue
|
|
36
|
+
_normalize_header(output, statement)
|
|
37
|
+
statement = []
|
|
38
|
+
_normalize_header(output, statement)
|
|
39
|
+
return "".join(output)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _mask_copy_input(source: str) -> str:
|
|
43
|
+
if "COPY" not in source.upper():
|
|
44
|
+
return source
|
|
45
|
+
output = list(source)
|
|
46
|
+
start = 0
|
|
47
|
+
for separator in re.finditer(r";", source):
|
|
48
|
+
if separator.start() < start:
|
|
49
|
+
continue
|
|
50
|
+
try:
|
|
51
|
+
tokens = sqlglot.tokenize(source[start : separator.end()], read="postgres")
|
|
52
|
+
except SqlglotError, RecursionError:
|
|
53
|
+
continue
|
|
54
|
+
if not tokens or tokens[-1].token_type is not TokenType.SEMICOLON:
|
|
55
|
+
continue
|
|
56
|
+
if start + tokens[-1].end != separator.start():
|
|
57
|
+
continue
|
|
58
|
+
if _copy_from_stdin(tokens):
|
|
59
|
+
marker = _COPY_END.search(source, separator.end())
|
|
60
|
+
end = marker.end() if marker is not None else len(source)
|
|
61
|
+
_blank(output, start, end)
|
|
62
|
+
start = end
|
|
63
|
+
else:
|
|
64
|
+
start = separator.end()
|
|
65
|
+
return "".join(output)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _normalize_header(output: list[str], tokens: Sequence[Token]) -> None:
|
|
69
|
+
if not _is_table_create(tokens):
|
|
70
|
+
return
|
|
71
|
+
depth = 0
|
|
72
|
+
for index, token in enumerate(tokens):
|
|
73
|
+
if token.token_type is TokenType.L_PAREN:
|
|
74
|
+
depth += 1
|
|
75
|
+
elif token.token_type is TokenType.R_PAREN:
|
|
76
|
+
depth -= 1
|
|
77
|
+
elif depth == 0 and token.token_type is TokenType.ALIAS:
|
|
78
|
+
spans = _ignored_header_spans(tokens[:index])
|
|
79
|
+
if not spans:
|
|
80
|
+
return
|
|
81
|
+
start = tokens[0].start
|
|
82
|
+
candidate = output[start : tokens[-1].end + 1]
|
|
83
|
+
for first, last in spans:
|
|
84
|
+
_blank(candidate, first.start - start, last.end + 1 - start)
|
|
85
|
+
if _is_query_create("".join(candidate)):
|
|
86
|
+
for first, last in spans:
|
|
87
|
+
_blank(output, first.start, last.end + 1)
|
|
88
|
+
return
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _temporary_qualifier(tokens: Sequence[Token]) -> Token | None:
|
|
92
|
+
if len(tokens) > 1 and tokens[1].token_type is TokenType.VAR and tokens[1].text.upper() in {"GLOBAL", "LOCAL"}:
|
|
93
|
+
return tokens[1]
|
|
94
|
+
return None
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _is_table_create(tokens: Sequence[Token]) -> bool:
|
|
98
|
+
kinds = tuple(token.token_type for token in tokens[:4])
|
|
99
|
+
if kinds[:2] == (TokenType.CREATE, TokenType.TABLE) or kinds[:3] == _TEMP_TABLE:
|
|
100
|
+
return True
|
|
101
|
+
if kinds[:3] == (TokenType.CREATE, TokenType.VAR, TokenType.TABLE):
|
|
102
|
+
return tokens[1].text.upper() == "UNLOGGED"
|
|
103
|
+
return (
|
|
104
|
+
kinds == (TokenType.CREATE, TokenType.VAR, TokenType.TEMPORARY, TokenType.TABLE)
|
|
105
|
+
and _temporary_qualifier(tokens) is not None
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _ignored_header_spans(tokens: Sequence[Token]) -> tuple[tuple[Token, Token], ...]:
|
|
110
|
+
spans: list[tuple[Token, Token]] = []
|
|
111
|
+
qualifier = _temporary_qualifier(tokens)
|
|
112
|
+
if qualifier is not None:
|
|
113
|
+
spans.append((qualifier, qualifier))
|
|
114
|
+
end = len(tokens)
|
|
115
|
+
if _has_tablespace_property(tokens):
|
|
116
|
+
spans.append((tokens[-2], tokens[-1]))
|
|
117
|
+
end -= 2
|
|
118
|
+
commit_start = _commit_property_start(tokens, end)
|
|
119
|
+
if commit_start < end and tokens[end - 1].token_type is TokenType.DROP:
|
|
120
|
+
spans.append((tokens[commit_start], tokens[end - 1]))
|
|
121
|
+
if _has_without_oids_property(tokens[:commit_start]):
|
|
122
|
+
spans.append((tokens[commit_start - 2], tokens[commit_start - 1]))
|
|
123
|
+
return tuple(spans)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _commit_property_start(tokens: Sequence[Token], end: int) -> int:
|
|
127
|
+
if tuple(token.token_type for token in tokens[end - 3 : end]) == _ON_COMMIT_DROP:
|
|
128
|
+
return end - 3
|
|
129
|
+
if end < _ON_COMMIT_ROWS_SIZE or tuple(
|
|
130
|
+
token.token_type for token in tokens[end - _ON_COMMIT_ROWS_SIZE : end - 2]
|
|
131
|
+
) != (TokenType.ON, TokenType.COMMIT):
|
|
132
|
+
return end
|
|
133
|
+
action, rows = tokens[end - 2 : end]
|
|
134
|
+
if rows.token_type is TokenType.ROWS and (
|
|
135
|
+
action.token_type is TokenType.DELETE
|
|
136
|
+
or (action.token_type is TokenType.VAR and action.text.upper() == "PRESERVE")
|
|
137
|
+
):
|
|
138
|
+
return end - _ON_COMMIT_ROWS_SIZE
|
|
139
|
+
return end
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _has_without_oids_property(tokens: Sequence[Token]) -> bool:
|
|
143
|
+
return (
|
|
144
|
+
len(tokens) > 1
|
|
145
|
+
and tokens[-2].token_type is TokenType.VAR
|
|
146
|
+
and tokens[-1].token_type is TokenType.VAR
|
|
147
|
+
and tokens[-2].text.upper() == "WITHOUT"
|
|
148
|
+
and tokens[-1].text.upper() == "OIDS"
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _has_tablespace_property(tokens: Sequence[Token]) -> bool:
|
|
153
|
+
return (
|
|
154
|
+
len(tokens) > 1
|
|
155
|
+
and tokens[-2].token_type is TokenType.VAR
|
|
156
|
+
and tokens[-2].text.upper() == "TABLESPACE"
|
|
157
|
+
and tokens[-1].token_type in {TokenType.VAR, TokenType.IDENTIFIER}
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _is_query_create(candidate: str) -> bool:
|
|
162
|
+
try:
|
|
163
|
+
parsed = sqlglot.parse_one(candidate, read="postgres")
|
|
164
|
+
except SqlglotError, RecursionError:
|
|
165
|
+
return False
|
|
166
|
+
return (
|
|
167
|
+
isinstance(parsed, exp.Create)
|
|
168
|
+
and parsed.args.get("kind") == "TABLE"
|
|
169
|
+
and isinstance(parsed.args.get("expression"), exp.Query)
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _copy_from_stdin(tokens: Sequence[Token]) -> bool:
|
|
174
|
+
if not tokens or tokens[0].token_type is not TokenType.COPY:
|
|
175
|
+
return False
|
|
176
|
+
depth = 0
|
|
177
|
+
for index, token in enumerate(tokens[:-1]):
|
|
178
|
+
if token.token_type is TokenType.L_PAREN:
|
|
179
|
+
depth += 1
|
|
180
|
+
elif token.token_type is TokenType.R_PAREN:
|
|
181
|
+
depth -= 1
|
|
182
|
+
elif depth == 0 and token.token_type is TokenType.FROM:
|
|
183
|
+
following = tokens[index + 1]
|
|
184
|
+
return following.token_type is TokenType.VAR and following.text.upper() == "STDIN"
|
|
185
|
+
return False
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _blank(output: list[str], start: int, end: int) -> None:
|
|
189
|
+
for index in range(start, end):
|
|
190
|
+
if output[index] not in {"\r", "\n"}:
|
|
191
|
+
output[index] = " "
|
|
@@ -87,6 +87,7 @@ _NATIVE_CONNECTIONS = frozenset(
|
|
|
87
87
|
)
|
|
88
88
|
_SELECT = re.compile(r"\bSELECT\b", re.IGNORECASE)
|
|
89
89
|
_PLACEHOLDER = re.compile(r"%(?:\([^)]+\))?s")
|
|
90
|
+
_POSTGRES_PLACEHOLDER = re.compile(r"%%|%(?:\([^)]+\))?[sbt]")
|
|
90
91
|
_FORMAT_HOLE = re.compile(r"(?<!\{)\{(?:[A-Za-z_]\w*|\d*)\}(?!\})")
|
|
91
92
|
_SQL_HOLE = "__sarj_sql_hole__"
|
|
92
93
|
_MAX_WRAPPER_DEPTH = 8
|
|
@@ -127,11 +128,19 @@ def query_signal(sql: str, *, dialect: str = "postgres") -> str | None:
|
|
|
127
128
|
|
|
128
129
|
|
|
129
130
|
def _prepared_sql(sql: str, dialect: str) -> str:
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
parameters = _POSTGRES_PLACEHOLDER if dialect == "postgres" else _PLACEHOLDER
|
|
132
|
+
prepared = _FORMAT_HOLE.sub(
|
|
133
|
+
_SQL_HOLE,
|
|
134
|
+
parameters.sub(lambda match: ("%" if match.group() == "%%" else "?").ljust(len(match.group())), sql),
|
|
135
|
+
)
|
|
136
|
+
if dialect == "postgres":
|
|
137
|
+
from sarj_python_lint.rules._postgres_ctas import normalize_postgres_ctas # ruff: ignore[import-outside-top-level] -- recover PostgreSQL temporary-table queries only after the SELECT gate.
|
|
138
|
+
|
|
139
|
+
prepared = normalize_postgres_ctas(prepared)
|
|
140
|
+
if "EXPLAIN" in prepared.upper():
|
|
141
|
+
from sarj_python_lint.rules._sql_explain import normalize_postgres_explain # ruff: ignore[import-outside-top-level] -- only executing EXPLAIN needs native token normalization.
|
|
133
142
|
|
|
134
|
-
|
|
143
|
+
prepared = normalize_postgres_ctas(normalize_postgres_explain(prepared))
|
|
135
144
|
if "GROUP" in prepared.upper() and ("/*" in prepared or "--" in prepared):
|
|
136
145
|
import sqlglot # ruff: ignore[import-outside-top-level] -- tokenize only GROUP candidates with comments.
|
|
137
146
|
|
|
@@ -173,13 +182,14 @@ def _statement_signal(statement: exp.Expr, sql: str, dialect: str) -> str | None
|
|
|
173
182
|
|
|
174
183
|
|
|
175
184
|
def transactional_queries(context: PythonFileContext) -> Iterator[TransactionalQuery]:
|
|
176
|
-
|
|
185
|
+
queries = tuple(_recover_queries(context))
|
|
186
|
+
if not queries:
|
|
177
187
|
return
|
|
178
188
|
dialects = _source_dialects(context)
|
|
179
189
|
if not dialects or dialects == {"analytical"}:
|
|
180
190
|
return
|
|
181
191
|
single = next(iter(dialects)) if len(dialects) == 1 else None
|
|
182
|
-
for candidate in
|
|
192
|
+
for candidate in queries:
|
|
183
193
|
dialect = single or _executing_dialect(candidate.node, context)
|
|
184
194
|
if dialect is not None and dialect != "analytical":
|
|
185
195
|
yield TransactionalQuery(candidate.node, candidate.sql, dialect)
|
|
@@ -34,7 +34,7 @@ _COMMON_AGGREGATE = re.compile(
|
|
|
34
34
|
re.IGNORECASE,
|
|
35
35
|
)
|
|
36
36
|
_LOCKING_READ = re.compile(r"\b(?:FOR\s+(?:NO\s+KEY\s+)?UPDATE|FOR\s+SHARE|SKIP\s+LOCKED)\b", re.IGNORECASE)
|
|
37
|
-
_PLACEHOLDER = re.compile(r"
|
|
37
|
+
_PLACEHOLDER = re.compile(r"%%|%(?:\([^)]+\))?[sbt]")
|
|
38
38
|
_GROUP_KEYS_LIMIT = 2
|
|
39
39
|
_GROUP_AGGREGATES_LIMIT = 2
|
|
40
40
|
_SINGLE_GROUP_AGGREGATES_LIMIT = 3
|
|
@@ -68,7 +68,9 @@ def _grouped_reporting_signal(sql: str) -> str | None:
|
|
|
68
68
|
if _GROUP_BY.search(sql) is None or _COMMON_AGGREGATE.search(sql) is None:
|
|
69
69
|
return None
|
|
70
70
|
try:
|
|
71
|
-
statements = parse_postgres(
|
|
71
|
+
statements = parse_postgres(
|
|
72
|
+
_PLACEHOLDER.sub(lambda match: ("%" if match.group() == "%%" else "?").ljust(len(match.group())), sql)
|
|
73
|
+
)
|
|
72
74
|
except SqlglotError, RecursionError:
|
|
73
75
|
return None
|
|
74
76
|
for statement in statements:
|
|
@@ -141,7 +143,7 @@ class NoAnalyticalAggregationInPostgresStore(Rule):
|
|
|
141
143
|
aliases=("no-aggregation-in-store-query", "no-analytical-queries-in-transactional-db"),
|
|
142
144
|
limitations=(
|
|
143
145
|
"Statically recoverable SQL in non-test, non-generated Python modules with native PostgreSQL, MySQL, or SQLite imports is analyzed, regardless of filename. The historical SARJ020 identifier is retained.",
|
|
144
|
-
"Every parsed SELECT DISTINCT (including DISTINCT ON), deduplicating UNION/INTERSECT/EXCEPT, GROUP BY, and built-in SQL aggregate is reported, including CTEs, nested writes, windowed aggregates, identity-bounded queries, and LIMIT queries. ALL set operations remain valid. This deliberately replaces the former reporting-size thresholds.",
|
|
146
|
+
"Every parsed SELECT DISTINCT (including DISTINCT ON), deduplicating UNION/INTERSECT/EXCEPT, GROUP BY, and built-in SQL aggregate is reported, including temporary-table AS queries, CTEs, nested writes, windowed aggregates, identity-bounded queries, and LIMIT queries. ALL set operations remain valid. This deliberately replaces the former reporting-size thresholds.",
|
|
145
147
|
"A single imported backend owns module SQL. Resolvable first-party query contracts and re-exports retain their native analytical-provider evidence. Mixed backend modules require a direct query sink on a source-proven native connection or annotated parameter; unresolved receivers and separately bound queries abstain.",
|
|
146
148
|
"Known ClickHouse, BigQuery, DuckDB, Snowflake, Trino, Athena, and Databricks drivers are analytical owners. Comments, scalar SQL values, identifiers, Python docstrings, and IS DISTINCT FROM do not trigger the policy.",
|
|
147
149
|
"SQLite multi-argument MIN/MAX and MySQL ANY_VALUE retain their scalar semantics; PostgreSQL ANY_VALUE remains an aggregate.",
|
|
@@ -165,6 +167,40 @@ class NoAnalyticalAggregationInPostgresStore(Rule):
|
|
|
165
167
|
expected_count=1,
|
|
166
168
|
public=True,
|
|
167
169
|
),
|
|
170
|
+
RuleExample(
|
|
171
|
+
example_id="temporary-table-distinct",
|
|
172
|
+
scenario="temporary-table",
|
|
173
|
+
title="A temporary PostgreSQL table still performs deduplication",
|
|
174
|
+
outcome=ExampleOutcome.MATCH,
|
|
175
|
+
files=(
|
|
176
|
+
ExampleFile.python(
|
|
177
|
+
"app/event_store.py",
|
|
178
|
+
"import psycopg\n\n"
|
|
179
|
+
'QUERY = "CREATE TEMP TABLE report ON COMMIT DROP AS WITH rows AS '
|
|
180
|
+
'(SELECT DISTINCT team_id FROM event) SELECT team_id FROM rows"\n',
|
|
181
|
+
),
|
|
182
|
+
),
|
|
183
|
+
focus_path=PurePosixPath("app/event_store.py"),
|
|
184
|
+
expected_count=1,
|
|
185
|
+
public=True,
|
|
186
|
+
),
|
|
187
|
+
RuleExample(
|
|
188
|
+
example_id="temporary-table-operational-read",
|
|
189
|
+
scenario="temporary-table",
|
|
190
|
+
title="A temporary PostgreSQL table can materialize an operational row lookup",
|
|
191
|
+
outcome=ExampleOutcome.NO_MATCH,
|
|
192
|
+
files=(
|
|
193
|
+
ExampleFile.python(
|
|
194
|
+
"app/event_store.py",
|
|
195
|
+
"import psycopg\n\n"
|
|
196
|
+
'QUERY = "CREATE TEMP TABLE report ON COMMIT DROP AS WITH rows AS '
|
|
197
|
+
'(SELECT team_id FROM event WHERE id = %s) SELECT team_id FROM rows"\n',
|
|
198
|
+
),
|
|
199
|
+
),
|
|
200
|
+
focus_path=PurePosixPath("app/event_store.py"),
|
|
201
|
+
expected_count=0,
|
|
202
|
+
public=True,
|
|
203
|
+
),
|
|
168
204
|
RuleExample(
|
|
169
205
|
example_id="operational-existence-lookup",
|
|
170
206
|
title="PostgreSQL performs an operational existence lookup",
|
|
@@ -15,6 +15,7 @@ from sarj_python_lint.rule_base import (
|
|
|
15
15
|
RuleExample,
|
|
16
16
|
Severity,
|
|
17
17
|
)
|
|
18
|
+
from sarj_python_lint.rules._local_source import LocalSourceFacts
|
|
18
19
|
from sarj_python_lint.rules._native_object_contracts import builtin_object, builtin_symbol
|
|
19
20
|
from sarj_python_lint.rules._opaque_contracts import REFINEMENT_TYPES, OpaqueContractFacts
|
|
20
21
|
from sarj_python_lint.rules.require_pydantic_for_mapping_shape import MappingShapeFacts
|
|
@@ -48,7 +49,7 @@ class PreferPreciseObjectContract(Rule):
|
|
|
48
49
|
"Safe fixes narrow only a bare builtin object return annotation to builtin str for a closed private nested synchronous helper returning one exact string literal, with every call used directly as an if test and all containing return contracts explicit. Existing inert/metadata/binding proofs must hold; public/domain/container/parameter/model contracts and other result uses remain review-only.",
|
|
49
50
|
"Checks builtin object in function signatures and class field annotations, including supported containers, callables, optional unions and quoted annotations. Local opaque values, object() sentinels, Literal/Annotated metadata, framework hooks, proven override signatures, and registered raw Pydantic callbacks are excluded. Functions that directly validate an object parameter through a source-visible BaseModel, BaseSettings or RootModel model_validate call, positionally or with obj=, retain that raw boundary. JSON text inputs still require a text or byte contract. Aliases must resolve to their source declaration and their bodies use definition scope. Alias graphs are bounded and shared branches reuse their facts. Imported or shadowed application types named object are preserved. Genuine opaque public contracts can use an explained exact-code exception; narrowing outside the exact private truthiness-only subset remains manual.",
|
|
50
51
|
"An import-proven TypeGuard or TypeIs retains bare object on its guarded positional parameter and unchecked object slots in its declared refinement result; other object parameters remain checked. Guard correctness belongs to the type-guard rules. Universal type[object] class contracts and the return of a canonical module-level PEP 562 __getattr__ hook retain their opaque runtime contracts.",
|
|
51
|
-
"Ordinary raw validators retain object inputs tied to builtin isinstance, exact builtin type comparisons or an actual source-resolved TypeGuard/TypeIs through rejecting branches, actual type/refinement assertions, accepting terminal branches with a rejecting fallback, or conditional expressions. Stable projections from containers with unchecked value slots retain their raw root contract when those values are validated. Source-visible local and imported validators may delegate those inputs and raw results; precise result narrowing does not justify a bare object output. Related unchecked mapping projections and transforms retain unknown values; import-proven native parsers and JSONDecoder preserve raw outputs. Universal builtin and stdlib interoperation may retain raw inputs. Independent object parameters, domain constructors and unproven parser names remain checked. Source resolution and dataflow
|
|
52
|
+
"Ordinary raw validators retain object inputs tied to builtin isinstance, exact builtin type comparisons or an actual source-resolved TypeGuard/TypeIs through rejecting branches, actual type/refinement assertions, accepting terminal branches with a rejecting fallback, or conditional expressions. Stable projections from containers with unchecked value slots retain their raw root contract when those values are validated. Source-visible local and imported validators may delegate those inputs and raw results; precise result narrowing does not justify a bare object output. Related unchecked mapping projections and transforms retain unknown values; import-proven native parsers and JSONDecoder preserve raw outputs. Universal builtin and stdlib interoperation may retain raw inputs. Independent object parameters, domain constructors and unproven parser names remain checked. Source resolution and dataflow use a bounded per-file proof cache, captured source inputs and cycle guards; rebinding, decorators and namespace mutation invalidate delegated proof.",
|
|
52
53
|
"Native opaque contracts include canonical ast.Constant.value reads and captures, FunctionType invocations, identity-only inputs and sys.getrefcount. Actual exec/eval globals and locals retain unknown values only through bounded native dict construction and alias flow; unrelated dictionaries and source domain factories do not borrow that ownership. Stub property returns on an import-proven runtime_checkable Protocol retain unchecked incoming attributes. Generic callable results, ordinary Protocol methods, application properties and unused parameters remain checked.",
|
|
53
54
|
"Raw input unions may include scalar or None branches; only genuine unchecked container branches seed raw projections. Mapping consumers that inspect only keys retain uninspected value slots. Projected aliases require simple statement dominance, and precise active guards permit typed consumption after validation. Native namespace output reads require a preceding direct function-scope execution and abstain after authored mutations. Benign builtins imports do not hide builtin object contracts; explicit object shadowing and source-visible object mutations remain outside scope.",
|
|
54
55
|
"An import-proven Iterable of unchecked values retains its raw element contract when every input use is a direct synchronous iteration and every reachable element read directly enters source-proven Pydantic model_validate. Deferred closures, rebinding, other iterator/element uses, unknown model providers and JSON-text parsers do not establish that boundary.",
|
|
@@ -131,7 +132,9 @@ class PreferPreciseObjectContract(Rule):
|
|
|
131
132
|
if facts.provenance.wildcard:
|
|
132
133
|
return []
|
|
133
134
|
findings: list[Diagnostic] = []
|
|
134
|
-
opaque = OpaqueContractFacts(
|
|
135
|
+
opaque = OpaqueContractFacts(
|
|
136
|
+
context, facts, local_source=LocalSourceFacts(source_inputs=context.session.source_inputs)
|
|
137
|
+
)
|
|
135
138
|
for owner, annotation in _contracts(context):
|
|
136
139
|
if not _has_object(annotation, context, facts, at=annotation):
|
|
137
140
|
continue
|