sarj-python-lint 1.64.0__tar.gz → 1.66.0__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.64.0 → sarj_python_lint-1.66.0}/.gitignore +3 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/PKG-INFO +1 -1
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/pyproject.toml +1 -1
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/_file_context.py +19 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/cast_access.py +3 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_annotation_semantics.py +4 -1
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_copy_on_write.py +2 -4
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_data_union_discriminator.py +1 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_pydantic_field_contract.py +2 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_resource_provenance.py +39 -28
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_sql.py +25 -15
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_store_writes.py +3 -3
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +2 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +2 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/duplicate_adjacent_exception_handler.py +3 -3
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/duplicate_closed_pure_helper.py +2 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/named_record_at_boundaries.py +1 -1
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_any_mapping_types.py +36 -30
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_broad_keyword_capture.py +3 -3
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_discarded_validation_result.py +3 -7
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_dual_shape_model_field_reader.py +1 -1
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_invalid_pydantic_bypass.py +2 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_invalid_pydantic_validator_return.py +2 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_loguru_printf_format.py +2 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_mutating_container_transform.py +1 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +32 -33
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_redundant_literal_description.py +2 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_select_star.py +73 -30
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_shallow_record_type_guard.py +2 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +1 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +2 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +2 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_declarative_batch_validation.py +1 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_discriminated_model_union.py +2 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +2 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +1 -1
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_native_string_check.py +2 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_psycopg_executemany.py +3 -3
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +2 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_required_constructor_parameters.py +2 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +1 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +1 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/redundant_test_constructor_forwarder.py +3 -3
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +1 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/require_precise_factory_signature.py +1 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/require_pydantic_for_mapping_shape.py +4 -6
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +2 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/unused_mock_setup.py +2 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/unused_test_factory_option.py +2 -2
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/LICENSE +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/README.md +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/__init__.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/__main__.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/_analysis_session.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/_filesystem.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/_python_target.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/_ratchet_cli.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/_secret_names.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/_source.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/_version.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/benchmark.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/interpreter_argv.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/json_boundary.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/py.typed +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/ratchet.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rule_base.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/__init__.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_ast_index.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_ast_position.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_closed_helpers.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_comments.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_docstrings.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_exports.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_fastapi.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_first_party.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_imports.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_inert_model_annotation.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_inherited_contract.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_local_source.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_logging.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_mapping_shape_callbacks.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_namespace_access.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_native_namespace_capability.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_paths.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_project_index.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_pytest.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_registry.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_resolved_operation_signature.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_route_shapes.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_runtime_bindings.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_set_fields.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_static_json_alias.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_test_composition.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_test_provenance.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_type_guard_symbols.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/delete_route_returns_no_content.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_async_function_cache.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_before_validator_input_mutation.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_blanket_suppression.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_conflicting_pydantic_alias_validation.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_contradictory_type_guard.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_create_verb_in_post_path.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_defaulted_environment_setting.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_duplicate_field_validator_body.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_exception_text_in_500_detail.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_fixed_sleep_in_loop.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_folded_bad_request_not_found.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_hasattr.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_impossible_pydantic_field_bounds.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_input_model_mutation.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_interpreter_source_arguments.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_loguru_exc_info.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_mocked_pydantic_value_object.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_partial_type_is.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_slash_collection_root_under_prefix.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_test_method_grafting.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_unknown_pydantic_validator_field.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_unused_copy_result.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/no_work_verb_get_route.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_bulk_upsert.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/repeated_unimplemented_test_contract.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/require_exp_on_jwt_decode.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/require_injectable_retry_sleep.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/stepdown.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/store_field_update_reuses_upsert.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/test_without_explicit_oracle.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
- {sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/suppression_policy.py +0 -0
|
@@ -44,6 +44,9 @@ Thumbs.db
|
|
|
44
44
|
!.claude/skills/test-value/
|
|
45
45
|
.claude/skills/test-value/*
|
|
46
46
|
!.claude/skills/test-value/SKILL.md
|
|
47
|
+
!.claude/skills/100-passes/
|
|
48
|
+
.claude/skills/100-passes/*
|
|
49
|
+
!.claude/skills/100-passes/SKILL.md
|
|
47
50
|
apps/docs/.wrangler/
|
|
48
51
|
apps/docs/.dev.vars*
|
|
49
52
|
!apps/docs/.dev.vars.example
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sarj-python-lint
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.66.0
|
|
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/
|
|
@@ -6,6 +6,7 @@ from typing import TYPE_CHECKING, final
|
|
|
6
6
|
|
|
7
7
|
from sarj_python_lint._analysis_session import AnalysisSession
|
|
8
8
|
from sarj_python_lint._source import symbol_prefilter_source
|
|
9
|
+
from sarj_python_lint.rules._annotation_semantics import AnnotationSemantics
|
|
9
10
|
from sarj_python_lint.rules._ast_index import NodeIndex
|
|
10
11
|
from sarj_python_lint.rules._fastapi import FastapiIndex
|
|
11
12
|
from sarj_python_lint.rules._imports import ImportIndex
|
|
@@ -18,6 +19,7 @@ if TYPE_CHECKING:
|
|
|
18
19
|
from pathlib import Path
|
|
19
20
|
|
|
20
21
|
from sarj_python_lint.rules._copy_on_write import CopyOnWriteAnalysis
|
|
22
|
+
from sarj_python_lint.rules._resource_provenance import ResourceProvenance
|
|
21
23
|
from sarj_python_lint.rules._test_provenance import TestProvenance
|
|
22
24
|
|
|
23
25
|
|
|
@@ -91,6 +93,10 @@ class PythonFileContext:
|
|
|
91
93
|
def module_imports(self) -> ImportIndex:
|
|
92
94
|
return ImportIndex.from_tree(self._valid_tree(), module_scope_only=True)
|
|
93
95
|
|
|
96
|
+
@cached_property
|
|
97
|
+
def annotation_semantics(self) -> AnnotationSemantics:
|
|
98
|
+
return AnnotationSemantics.from_imports(self._valid_tree(), self.module_imports)
|
|
99
|
+
|
|
94
100
|
@cached_property
|
|
95
101
|
def dynamic_namespace(self) -> bool:
|
|
96
102
|
return dynamic_namespace_access(self.nodes(ast.AST), self.imports, self.parents)
|
|
@@ -117,3 +123,16 @@ class PythonFileContext:
|
|
|
117
123
|
from sarj_python_lint.rules._copy_on_write import CopyOnWriteAnalysis # ruff: ignore[import-outside-top-level] — share ownership analysis only when requested
|
|
118
124
|
|
|
119
125
|
return CopyOnWriteAnalysis(self)
|
|
126
|
+
|
|
127
|
+
@cached_property
|
|
128
|
+
def resource_provenance(self) -> ResourceProvenance:
|
|
129
|
+
from sarj_python_lint.rules._resource_provenance import ResourceProvenance # ruff: ignore[import-outside-top-level] -- file-owned binding facts are lazy.
|
|
130
|
+
|
|
131
|
+
# The owner caches this analysis; borrowing prevents a reference cycle.
|
|
132
|
+
return ResourceProvenance(self, borrow_context=True)
|
|
133
|
+
|
|
134
|
+
@cached_property
|
|
135
|
+
def static_resource_provenance(self) -> ResourceProvenance:
|
|
136
|
+
from sarj_python_lint.rules._resource_provenance import ResourceProvenance # ruff: ignore[import-outside-top-level] -- keep static-namespace policy in a separate cached analysis.
|
|
137
|
+
|
|
138
|
+
return ResourceProvenance(self, require_static_namespace=True, borrow_context=True)
|
|
@@ -6,13 +6,14 @@ from typing import TYPE_CHECKING, Literal
|
|
|
6
6
|
|
|
7
7
|
from sarj_python_lint._file_context import PythonFileContext
|
|
8
8
|
from sarj_python_lint.rules._namespace_access import dynamic_namespace_access
|
|
9
|
-
from sarj_python_lint.rules._resource_provenance import ResourceProvenance
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
if TYPE_CHECKING:
|
|
13
12
|
from collections.abc import Iterator
|
|
14
13
|
from pathlib import Path
|
|
15
14
|
|
|
15
|
+
from sarj_python_lint.rules._resource_provenance import ResourceProvenance
|
|
16
|
+
|
|
16
17
|
|
|
17
18
|
_TYPING = frozenset({"typing", "typing_extensions"})
|
|
18
19
|
_GETATTR_ARITIES = frozenset({2, 3})
|
|
@@ -44,7 +45,7 @@ def indirect_typing_cast_accesses(path: Path, source: str) -> tuple[CastAccess,
|
|
|
44
45
|
|
|
45
46
|
|
|
46
47
|
def _reflection_accesses(context: PythonFileContext) -> list[CastAccess]:
|
|
47
|
-
provenance =
|
|
48
|
+
provenance = context.resource_provenance
|
|
48
49
|
candidates = [
|
|
49
50
|
(node, receiver)
|
|
50
51
|
for node in context.nodes(ast.Call, ast.Subscript)
|
|
@@ -19,7 +19,10 @@ class AnnotationSemantics:
|
|
|
19
19
|
|
|
20
20
|
@classmethod
|
|
21
21
|
def from_tree(cls, tree: ast.Module, *, module_scope_only: bool = True) -> Self:
|
|
22
|
-
|
|
22
|
+
return cls.from_imports(tree, ImportIndex.from_tree(tree, module_scope_only=module_scope_only))
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def from_imports(cls, tree: ast.Module, imports: ImportIndex) -> Self:
|
|
23
26
|
candidates: dict[str, ast.expr] = {}
|
|
24
27
|
ambiguous: set[str] = set()
|
|
25
28
|
for statement in tree.body:
|
{sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_copy_on_write.py
RENAMED
|
@@ -110,9 +110,7 @@ class _Models:
|
|
|
110
110
|
def validation_owner(self, unit: SourceUnit) -> _ValidationOwner:
|
|
111
111
|
if unit.path not in self._validation_owners:
|
|
112
112
|
context = PythonFileContext(unit.path, unit.source, self._validation_session)
|
|
113
|
-
self._validation_owners[unit.path] = _ValidationOwner(
|
|
114
|
-
context, ResourceProvenance(context, require_static_namespace=True)
|
|
115
|
-
)
|
|
113
|
+
self._validation_owners[unit.path] = _ValidationOwner(context, context.static_resource_provenance)
|
|
116
114
|
return self._validation_owners[unit.path]
|
|
117
115
|
|
|
118
116
|
def annotations(self, unit: SourceUnit) -> AnnotationSemantics:
|
|
@@ -378,7 +376,7 @@ class CopyOnWriteAnalysis:
|
|
|
378
376
|
|
|
379
377
|
@cached_property
|
|
380
378
|
def _validator_provider(self) -> ResourceProvenance:
|
|
381
|
-
return
|
|
379
|
+
return self.context.static_resource_provenance
|
|
382
380
|
|
|
383
381
|
def _function(self, function: _Function) -> None:
|
|
384
382
|
parameters = [*function.args.posonlyargs, *function.args.args, *function.args.kwonlyargs]
|
|
@@ -72,6 +72,7 @@ def data_union_diagnostics(context: PythonFileContext, code: str) -> list[Diagno
|
|
|
72
72
|
class _DataUnions:
|
|
73
73
|
def __init__(self, context: PythonFileContext, tree: ast.Module) -> None:
|
|
74
74
|
self.context = context
|
|
75
|
+
# This analysis refines mutation ownership; keep its provenance private.
|
|
75
76
|
self.provenance = ResourceProvenance(context, require_static_namespace=True)
|
|
76
77
|
self.provenance.mutated = _scoped_module_mutations(self.provenance, tree)
|
|
77
78
|
bindings = self.provenance.bindings.get(tree, {})
|
|
@@ -13,11 +13,11 @@ from sarj_python_lint.json_boundary import is_object_mapping
|
|
|
13
13
|
from sarj_python_lint.rules._first_party import distribution_root
|
|
14
14
|
from sarj_python_lint.rules._namespace_access import dynamic_namespace_access
|
|
15
15
|
from sarj_python_lint.rules._native_namespace_capability import native_namespace_capability_escapes
|
|
16
|
-
from sarj_python_lint.rules._resource_provenance import ResourceProvenance
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
if TYPE_CHECKING:
|
|
20
19
|
from sarj_python_lint._file_context import PythonFileContext
|
|
20
|
+
from sarj_python_lint.rules._resource_provenance import ResourceProvenance
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
MODEL_SOURCES = frozenset({"pydantic", "pydantic.main"})
|
|
@@ -43,7 +43,7 @@ def direct_models(context: PythonFileContext, *, methods: bool = False) -> tuple
|
|
|
43
43
|
or dynamic_namespace_access(context.nodes(ast.AST), context.imports, context.parents)
|
|
44
44
|
):
|
|
45
45
|
return ()
|
|
46
|
-
provenance =
|
|
46
|
+
provenance = context.static_resource_provenance
|
|
47
47
|
return tuple(
|
|
48
48
|
node
|
|
49
49
|
for node in tree.body
|
|
@@ -5,9 +5,9 @@ from collections import defaultdict
|
|
|
5
5
|
from functools import cached_property
|
|
6
6
|
from types import MappingProxyType
|
|
7
7
|
from typing import TYPE_CHECKING, final
|
|
8
|
+
from weakref import ReferenceType, ref
|
|
8
9
|
|
|
9
10
|
from sarj_python_lint.rules._ast_index import has_own_yield
|
|
10
|
-
from sarj_python_lint.rules._namespace_access import dynamic_namespace_access
|
|
11
11
|
from sarj_python_lint.rules._runtime_bindings import RuntimeBindings
|
|
12
12
|
|
|
13
13
|
|
|
@@ -71,8 +71,13 @@ def builtin_namespace_untouched(context: PythonFileContext) -> bool:
|
|
|
71
71
|
|
|
72
72
|
@final
|
|
73
73
|
class ResourceProvenance:
|
|
74
|
-
def __init__(
|
|
75
|
-
self
|
|
74
|
+
def __init__(
|
|
75
|
+
self, context: PythonFileContext, *, require_static_namespace: bool = False, borrow_context: bool = False
|
|
76
|
+
) -> None:
|
|
77
|
+
self._context: PythonFileContext | ReferenceType[PythonFileContext] = (
|
|
78
|
+
ref(context) if borrow_context else context
|
|
79
|
+
)
|
|
80
|
+
self.parents = context.parents
|
|
76
81
|
self.require_static_namespace = require_static_namespace
|
|
77
82
|
self.bindings: dict[ast.AST | None, dict[str, list[ast.AST]]] = defaultdict(lambda: defaultdict(list))
|
|
78
83
|
self.reads: dict[str, list[ast.Name]] = defaultdict(list)
|
|
@@ -98,15 +103,23 @@ class ResourceProvenance:
|
|
|
98
103
|
if root is not None:
|
|
99
104
|
self.mutated.add(root)
|
|
100
105
|
|
|
106
|
+
@property
|
|
107
|
+
def context(self) -> PythonFileContext:
|
|
108
|
+
context = self._context() if isinstance(self._context, ReferenceType) else self._context
|
|
109
|
+
if context is None:
|
|
110
|
+
msg = "The provenance file context has been released"
|
|
111
|
+
raise ReferenceError(msg)
|
|
112
|
+
return context
|
|
113
|
+
|
|
101
114
|
@cached_property
|
|
102
115
|
def builtin_namespace_untouched(self) -> bool:
|
|
103
116
|
return builtin_namespace_untouched(self.context)
|
|
104
117
|
|
|
105
118
|
def scope(self, node: ast.AST) -> ast.AST | None:
|
|
106
|
-
parent = self.
|
|
119
|
+
parent = self.parents.get(node)
|
|
107
120
|
while parent is not None:
|
|
108
121
|
if isinstance(parent, ast.arguments) and (node in parent.defaults or node in parent.kw_defaults):
|
|
109
|
-
parent = self.
|
|
122
|
+
parent = self.parents.get(parent)
|
|
110
123
|
elif isinstance(parent, _SCOPES) and not (
|
|
111
124
|
(
|
|
112
125
|
isinstance(parent, ast.FunctionDef | ast.AsyncFunctionDef | ast.ClassDef)
|
|
@@ -118,12 +131,12 @@ class ResourceProvenance:
|
|
|
118
131
|
if parent is None:
|
|
119
132
|
return None
|
|
120
133
|
node = parent
|
|
121
|
-
parent = self.
|
|
134
|
+
parent = self.parents.get(parent)
|
|
122
135
|
return None
|
|
123
136
|
|
|
124
137
|
def _binding_scope(self, node: ast.AST) -> ast.AST | None:
|
|
125
138
|
scope = self.scope(node)
|
|
126
|
-
parent = self.
|
|
139
|
+
parent = self.parents.get(node)
|
|
127
140
|
if isinstance(parent, ast.NamedExpr) and parent.target is node:
|
|
128
141
|
while isinstance(scope, ast.ListComp | ast.SetComp | ast.DictComp | ast.GeneratorExp):
|
|
129
142
|
scope = self.scope(scope)
|
|
@@ -155,7 +168,7 @@ class ResourceProvenance:
|
|
|
155
168
|
binding = self.runtime_binding(root, node)
|
|
156
169
|
if not isinstance(binding, ast.alias):
|
|
157
170
|
return None
|
|
158
|
-
qualified = import_name_for_binding(node, binding, self.
|
|
171
|
+
qualified = import_name_for_binding(node, binding, self.parents.get(binding))
|
|
159
172
|
if qualified is None or not self._owner_namespace_untouched(qualified.partition(".")[0]):
|
|
160
173
|
return None
|
|
161
174
|
if binding not in self.runtime_import_cache:
|
|
@@ -195,7 +208,7 @@ class ResourceProvenance:
|
|
|
195
208
|
def _namespace_aliases(self) -> dict[str, tuple[ast.alias, ...]]:
|
|
196
209
|
aliases: dict[str, list[ast.alias]] = defaultdict(list)
|
|
197
210
|
for binding in self.context.nodes(ast.alias):
|
|
198
|
-
parent = self.
|
|
211
|
+
parent = self.parents.get(binding)
|
|
199
212
|
name = binding.asname or (
|
|
200
213
|
binding.name.partition(".")[0] if isinstance(parent, ast.Import) else binding.name
|
|
201
214
|
)
|
|
@@ -231,7 +244,7 @@ class ResourceProvenance:
|
|
|
231
244
|
return paths
|
|
232
245
|
|
|
233
246
|
def _namespace_module_path(self, binding: ast.alias, attributes: tuple[str, ...]) -> Path | None:
|
|
234
|
-
parent = self.
|
|
247
|
+
parent = self.parents.get(binding)
|
|
235
248
|
match parent:
|
|
236
249
|
case ast.Import():
|
|
237
250
|
prefix = binding.name if binding.asname else binding.name.partition(".")[0]
|
|
@@ -250,7 +263,7 @@ class ResourceProvenance:
|
|
|
250
263
|
for node in nodes:
|
|
251
264
|
if not isinstance(node, ast.alias):
|
|
252
265
|
return False
|
|
253
|
-
parent = self.
|
|
266
|
+
parent = self.parents.get(node)
|
|
254
267
|
if isinstance(parent, ast.Import):
|
|
255
268
|
targets.add(("import", None, 0, node.name))
|
|
256
269
|
elif isinstance(parent, ast.ImportFrom):
|
|
@@ -271,7 +284,7 @@ class ResourceProvenance:
|
|
|
271
284
|
return False
|
|
272
285
|
binding = self.binding(root, node)
|
|
273
286
|
for read in self.reads.get(root, ()):
|
|
274
|
-
parent = self.
|
|
287
|
+
parent = self.parents.get(read)
|
|
275
288
|
if isinstance(parent, ast.Attribute | ast.ExceptHandler):
|
|
276
289
|
continue
|
|
277
290
|
if not self._safe_import_use(read):
|
|
@@ -317,7 +330,7 @@ class ResourceProvenance:
|
|
|
317
330
|
)
|
|
318
331
|
|
|
319
332
|
def _safe_import_use(self, node: ast.Name | ast.Attribute) -> bool:
|
|
320
|
-
parent = self.
|
|
333
|
+
parent = self.parents.get(node)
|
|
321
334
|
return (
|
|
322
335
|
(isinstance(parent, ast.Attribute) and parent.value is node)
|
|
323
336
|
or (isinstance(parent, ast.Call) and parent.func is node)
|
|
@@ -337,9 +350,9 @@ class ResourceProvenance:
|
|
|
337
350
|
binding = self.binding(name.id, at)
|
|
338
351
|
if not isinstance(binding, ast.Name):
|
|
339
352
|
return None
|
|
340
|
-
statement = self.
|
|
353
|
+
statement = self.parents.get(binding)
|
|
341
354
|
if isinstance(statement, ast.withitem):
|
|
342
|
-
owner = self.
|
|
355
|
+
owner = self.parents.get(statement)
|
|
343
356
|
if (
|
|
344
357
|
binding is statement.optional_vars
|
|
345
358
|
and self.contains(owner, at)
|
|
@@ -351,12 +364,12 @@ class ResourceProvenance:
|
|
|
351
364
|
return value if isinstance(value, ast.Call) else None
|
|
352
365
|
|
|
353
366
|
def assignment_value(self, binding: ast.Name, at: ast.AST) -> ast.expr | None:
|
|
354
|
-
statement = self.
|
|
367
|
+
statement = self.parents.get(binding)
|
|
355
368
|
if not isinstance(statement, ast.Assign | ast.AnnAssign):
|
|
356
369
|
return None
|
|
357
370
|
if isinstance(statement, ast.Assign) and len(statement.targets) != 1:
|
|
358
371
|
return None
|
|
359
|
-
if not isinstance(self.
|
|
372
|
+
if not isinstance(self.parents.get(statement), ast.Module | ast.FunctionDef | ast.AsyncFunctionDef):
|
|
360
373
|
return None
|
|
361
374
|
return statement.value if statement.lineno < getattr(at, "lineno", 0) else None
|
|
362
375
|
|
|
@@ -381,12 +394,10 @@ class ResourceProvenance:
|
|
|
381
394
|
|
|
382
395
|
@cached_property
|
|
383
396
|
def dynamic_namespace(self) -> bool:
|
|
384
|
-
return self.require_static_namespace and
|
|
385
|
-
self.context.nodes(ast.AST), self.context.imports, self.context.parents
|
|
386
|
-
)
|
|
397
|
+
return self.require_static_namespace and self.context.dynamic_namespace
|
|
387
398
|
|
|
388
399
|
def _stable_async_definition(self, function: ast.AsyncFunctionDef) -> ast.AsyncFunctionDef | None:
|
|
389
|
-
owner = self.
|
|
400
|
+
owner = self.parents.get(function)
|
|
390
401
|
if not isinstance(owner, ast.Module | ast.FunctionDef | ast.AsyncFunctionDef):
|
|
391
402
|
return None
|
|
392
403
|
if function.decorator_list or has_own_yield(function):
|
|
@@ -415,10 +426,10 @@ class ResourceProvenance:
|
|
|
415
426
|
return True
|
|
416
427
|
|
|
417
428
|
def _function_alias(self, read: ast.Name) -> ast.Name | None:
|
|
418
|
-
parent = self.
|
|
429
|
+
parent = self.parents.get(read)
|
|
419
430
|
if not isinstance(parent, ast.Assign | ast.AnnAssign) or parent.value is not read:
|
|
420
431
|
return None
|
|
421
|
-
if not isinstance(self.
|
|
432
|
+
if not isinstance(self.parents.get(parent), ast.Module | ast.FunctionDef | ast.AsyncFunctionDef):
|
|
422
433
|
return None
|
|
423
434
|
targets = parent.targets if isinstance(parent, ast.Assign) else [parent.target]
|
|
424
435
|
if len(targets) != 1 or not isinstance(targets[0], ast.Name):
|
|
@@ -427,7 +438,7 @@ class ResourceProvenance:
|
|
|
427
438
|
return target if self.binding(target.id, target) is target else None
|
|
428
439
|
|
|
429
440
|
def _safe_async_read(self, read: ast.Name) -> bool:
|
|
430
|
-
parent = self.
|
|
441
|
+
parent = self.parents.get(read)
|
|
431
442
|
if not isinstance(parent, ast.Call):
|
|
432
443
|
return False
|
|
433
444
|
if parent.func is read:
|
|
@@ -469,7 +480,7 @@ class ResourceProvenance:
|
|
|
469
480
|
return self.escape_cache[key]
|
|
470
481
|
|
|
471
482
|
def _method_or_context_read(self, read: ast.Name, *, allow_context: bool) -> bool:
|
|
472
|
-
parent = self.
|
|
483
|
+
parent = self.parents.get(read)
|
|
473
484
|
if allow_context and isinstance(parent, ast.withitem) and parent.context_expr is read:
|
|
474
485
|
return True
|
|
475
486
|
if (
|
|
@@ -478,12 +489,12 @@ class ResourceProvenance:
|
|
|
478
489
|
or parent.attr in {"__setattr__", "__delattr__", "__getattribute__"}
|
|
479
490
|
):
|
|
480
491
|
return False
|
|
481
|
-
call = self.
|
|
492
|
+
call = self.parents.get(parent)
|
|
482
493
|
return isinstance(call, ast.Call) and call.func is parent
|
|
483
494
|
|
|
484
495
|
def contains(self, owner: ast.AST | None, node: ast.AST) -> bool:
|
|
485
|
-
while node in self.
|
|
486
|
-
node = self.
|
|
496
|
+
while node in self.parents:
|
|
497
|
+
node = self.parents[node]
|
|
487
498
|
if node is owner:
|
|
488
499
|
return True
|
|
489
500
|
return False
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import ast
|
|
4
|
+
import re
|
|
4
5
|
from typing import TYPE_CHECKING
|
|
5
6
|
|
|
6
7
|
from sarj_python_lint.rules._paths import is_test_path
|
|
@@ -10,6 +11,15 @@ if TYPE_CHECKING:
|
|
|
10
11
|
from pathlib import Path
|
|
11
12
|
|
|
12
13
|
|
|
14
|
+
_SQL_LINE_END = re.compile(r"[\r\n]")
|
|
15
|
+
_CONTINUED_QUOTE = re.compile(r"[ \t\f\v]*(?:--[^\r\n]*)?[\r\n](?:[ \t\f\v\r\n]|--[^\r\n]*[\r\n])*'")
|
|
16
|
+
POSTGRES_IDENTIFIER_CONTINUATION = r"[A-Za-z0-9_$\u0080-\U0010ffff]"
|
|
17
|
+
POSTGRES_UNQUOTED_IDENTIFIER = rf"[A-Za-z_\u0080-\U0010ffff]{POSTGRES_IDENTIFIER_CONTINUATION}*"
|
|
18
|
+
SQL_WHITESPACE = " \t\r\n\f\v"
|
|
19
|
+
_IDENTIFIER_CONTINUATION = re.compile(POSTGRES_IDENTIFIER_CONTINUATION)
|
|
20
|
+
_DOLLAR_DELIMITER = re.compile(r"\$(?:[A-Za-z_\u0080-\U0010ffff][A-Za-z0-9_\u0080-\U0010ffff]*)?\$")
|
|
21
|
+
|
|
22
|
+
|
|
13
23
|
def is_store_module(path: Path) -> bool:
|
|
14
24
|
if is_test_path(path):
|
|
15
25
|
return False
|
|
@@ -44,6 +54,7 @@ def strip_sql_noise(
|
|
|
44
54
|
*,
|
|
45
55
|
mask_dollar_quotes: bool = True,
|
|
46
56
|
mask_double_quotes: bool = True,
|
|
57
|
+
preserve_quoted_tokens: bool = False,
|
|
47
58
|
) -> str:
|
|
48
59
|
out = list(text)
|
|
49
60
|
i = 0
|
|
@@ -56,8 +67,10 @@ def strip_sql_noise(
|
|
|
56
67
|
i += 1
|
|
57
68
|
continue
|
|
58
69
|
for offset in range(i, end):
|
|
59
|
-
if text[offset]
|
|
70
|
+
if text[offset] not in {"\n", "\r"}:
|
|
60
71
|
out[offset] = " "
|
|
72
|
+
if preserve_quoted_tokens and text[i] in {"'", '"', "$"}:
|
|
73
|
+
out[i] = "?"
|
|
61
74
|
i = end
|
|
62
75
|
return "".join(out)
|
|
63
76
|
|
|
@@ -68,7 +81,7 @@ def _quoted_sql_end(text: str, start: int) -> int:
|
|
|
68
81
|
quote == "'"
|
|
69
82
|
and start > 0
|
|
70
83
|
and text[start - 1] in {"E", "e"}
|
|
71
|
-
and (start == 1 or
|
|
84
|
+
and (start == 1 or _IDENTIFIER_CONTINUATION.match(text, start - 2) is None)
|
|
72
85
|
)
|
|
73
86
|
i = start + 1
|
|
74
87
|
while i < len(text):
|
|
@@ -82,6 +95,9 @@ def _quoted_sql_end(text: str, start: int) -> int:
|
|
|
82
95
|
if i < len(text) and text[i] == quote:
|
|
83
96
|
i += 1
|
|
84
97
|
continue
|
|
98
|
+
if escape_string and (continuation := _CONTINUED_QUOTE.match(text, i)) is not None:
|
|
99
|
+
i = continuation.end()
|
|
100
|
+
continue
|
|
85
101
|
break
|
|
86
102
|
return i
|
|
87
103
|
|
|
@@ -91,8 +107,8 @@ def _sql_noise_end(text: str, start: int, *, mask_dollar_quotes: bool) -> int |
|
|
|
91
107
|
if ch in {"'", '"'}:
|
|
92
108
|
return _quoted_sql_end(text, start)
|
|
93
109
|
if text.startswith("--", start) or (ch == "#" and (start == 0 or text[start - 1].isspace())):
|
|
94
|
-
end =
|
|
95
|
-
return len(text) if end
|
|
110
|
+
end = _SQL_LINE_END.search(text, start)
|
|
111
|
+
return len(text) if end is None else end.start()
|
|
96
112
|
if text.startswith("/*", start):
|
|
97
113
|
return _block_comment_end(text, start)
|
|
98
114
|
if mask_dollar_quotes and ch == "$":
|
|
@@ -116,17 +132,11 @@ def _block_comment_end(text: str, start: int) -> int:
|
|
|
116
132
|
|
|
117
133
|
|
|
118
134
|
def _dollar_quote_end(text: str, start: int) -> int | None:
|
|
119
|
-
if start > 0 and (text
|
|
135
|
+
if start > 0 and _IDENTIFIER_CONTINUATION.match(text, start - 1) is not None:
|
|
120
136
|
return None
|
|
121
|
-
|
|
122
|
-
if
|
|
123
|
-
return None
|
|
124
|
-
tag = text[start + 1 : delimiter_end]
|
|
125
|
-
valid_tag = not tag or (
|
|
126
|
-
(tag[0].isalpha() or tag[0] == "_") and all(char.isalnum() or char == "_" for char in tag[1:])
|
|
127
|
-
)
|
|
128
|
-
if not valid_tag:
|
|
137
|
+
match = _DOLLAR_DELIMITER.match(text, start)
|
|
138
|
+
if match is None:
|
|
129
139
|
return None
|
|
130
|
-
delimiter =
|
|
131
|
-
close = text.find(delimiter,
|
|
140
|
+
delimiter = match[0]
|
|
141
|
+
close = text.find(delimiter, match.end())
|
|
132
142
|
return None if close == -1 else close + len(delimiter)
|
{sarj_python_lint-1.64.0 → sarj_python_lint-1.66.0}/src/sarj_python_lint/rules/_store_writes.py
RENAMED
|
@@ -12,7 +12,6 @@ from sarj_python_lint.rules._annotation_semantics import AnnotationSemantics, sc
|
|
|
12
12
|
from sarj_python_lint.rules._ast_index import walk
|
|
13
13
|
from sarj_python_lint.rules._paths import is_generated
|
|
14
14
|
from sarj_python_lint.rules._project_index import ProjectIndexSet
|
|
15
|
-
from sarj_python_lint.rules._resource_provenance import ResourceProvenance
|
|
16
15
|
|
|
17
16
|
|
|
18
17
|
if TYPE_CHECKING:
|
|
@@ -20,6 +19,7 @@ if TYPE_CHECKING:
|
|
|
20
19
|
|
|
21
20
|
from sarj_python_lint._file_context import PythonFileContext
|
|
22
21
|
from sarj_python_lint.rules._imports import ImportIndex
|
|
22
|
+
from sarj_python_lint.rules._resource_provenance import ResourceProvenance
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
type Function = ast.FunctionDef | ast.AsyncFunctionDef
|
|
@@ -187,7 +187,7 @@ def _comprehension_scopes(
|
|
|
187
187
|
class StoreOwners:
|
|
188
188
|
def __init__(self, context: PythonFileContext) -> None:
|
|
189
189
|
self.context = context
|
|
190
|
-
self.provenance =
|
|
190
|
+
self.provenance = context.static_resource_provenance
|
|
191
191
|
self.project = context.session.project
|
|
192
192
|
|
|
193
193
|
def receiver(self, expression: ast.expr, at: ast.AST) -> tuple[ast.ClassDef, ImportIndex] | None:
|
|
@@ -290,7 +290,7 @@ class StoreOwners:
|
|
|
290
290
|
from sarj_python_lint._file_context import PythonFileContext # ruff: ignore[import-outside-top-level] -- defer to avoid the rule registry's context import cycle.
|
|
291
291
|
|
|
292
292
|
definition = PythonFileContext(owner.path, owner.source, self.context.session)
|
|
293
|
-
provenance =
|
|
293
|
+
provenance = definition.static_resource_provenance
|
|
294
294
|
if (
|
|
295
295
|
provenance.dynamic_namespace
|
|
296
296
|
or provenance.wildcard
|
|
@@ -16,11 +16,11 @@ from sarj_python_lint.rule_base import (
|
|
|
16
16
|
Severity,
|
|
17
17
|
is_suppressed,
|
|
18
18
|
)
|
|
19
|
-
from sarj_python_lint.rules._resource_provenance import ResourceProvenance
|
|
20
19
|
|
|
21
20
|
|
|
22
21
|
if TYPE_CHECKING:
|
|
23
22
|
from sarj_python_lint._file_context import PythonFileContext
|
|
23
|
+
from sarj_python_lint.rules._resource_provenance import ResourceProvenance
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
_BAD = "from contextlib import AsyncExitStack\nasync def close():\n await release()\nasync def run():\n async with AsyncExitStack() as stack:\n stack.callback(close)\n"
|
|
@@ -72,7 +72,7 @@ class AsyncCleanupRegisteredSynchronously(Rule):
|
|
|
72
72
|
def check_context(self, context: PythonFileContext) -> list[Diagnostic]:
|
|
73
73
|
if "callback" not in context.symbol_source or context.generated or context.tree is None:
|
|
74
74
|
return []
|
|
75
|
-
provenance =
|
|
75
|
+
provenance = context.static_resource_provenance
|
|
76
76
|
findings: list[Diagnostic] = []
|
|
77
77
|
for call in context.nodes(ast.Call):
|
|
78
78
|
if not _wrong_callback(call, provenance) or is_suppressed(context.source_lines, call.lineno, self.code):
|
|
@@ -21,7 +21,7 @@ from sarj_python_lint.rule_base import (
|
|
|
21
21
|
from sarj_python_lint.rules._ast_index import walk as walk_ast
|
|
22
22
|
from sarj_python_lint.rules._imports import ImportIndex
|
|
23
23
|
from sarj_python_lint.rules._pytest import collected_tests
|
|
24
|
-
from sarj_python_lint.rules._resource_provenance import
|
|
24
|
+
from sarj_python_lint.rules._resource_provenance import builtin_namespace_untouched
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
if TYPE_CHECKING:
|
|
@@ -291,7 +291,7 @@ def _test_diagnostics(
|
|
|
291
291
|
|
|
292
292
|
|
|
293
293
|
def _mock_provider_proven(test: _TestFunction, context: PythonFileContext) -> bool:
|
|
294
|
-
provenance =
|
|
294
|
+
provenance = context.static_resource_provenance
|
|
295
295
|
constructors = [
|
|
296
296
|
node
|
|
297
297
|
for node in ast.walk(test)
|
|
@@ -26,13 +26,13 @@ from sarj_python_lint.rule_base import (
|
|
|
26
26
|
from sarj_python_lint.rules._closed_helpers import dynamic_namespace, stable_class
|
|
27
27
|
from sarj_python_lint.rules._paths import is_generated
|
|
28
28
|
from sarj_python_lint.rules._project_index import ProjectIndexSet
|
|
29
|
-
from sarj_python_lint.rules._resource_provenance import ResourceProvenance
|
|
30
29
|
from sarj_python_lint.rules._suppression_comments import scan_comments
|
|
31
30
|
|
|
32
31
|
|
|
33
32
|
if TYPE_CHECKING:
|
|
34
33
|
from sarj_python_lint._file_context import PythonFileContext
|
|
35
34
|
from sarj_python_lint.rules._project_index import SourceUnit, SymbolRef
|
|
35
|
+
from sarj_python_lint.rules._resource_provenance import ResourceProvenance
|
|
36
36
|
from sarj_python_lint.rules._suppression_comments import Comment
|
|
37
37
|
|
|
38
38
|
|
|
@@ -85,7 +85,7 @@ class DuplicateAdjacentExceptionHandler(ProjectRule):
|
|
|
85
85
|
return []
|
|
86
86
|
project = context.session.project or ProjectIndexSet.single(context.path, context.source)
|
|
87
87
|
unit = project.unit_or_source(context.path, context.source, tree)
|
|
88
|
-
provenance =
|
|
88
|
+
provenance = context.resource_provenance
|
|
89
89
|
if not provenance.builtin_namespace_untouched:
|
|
90
90
|
return []
|
|
91
91
|
comments = scan_comments(context.source)
|
|
@@ -198,7 +198,7 @@ def _first_party_exception(
|
|
|
198
198
|
definition_context = (
|
|
199
199
|
context if owner.path == context.path else PythonFileContext(owner.path, owner.source, context.session)
|
|
200
200
|
)
|
|
201
|
-
definition_provenance = provenance if definition_context is context else
|
|
201
|
+
definition_provenance = provenance if definition_context is context else definition_context.resource_provenance
|
|
202
202
|
declaration = next(
|
|
203
203
|
(node for node in definition_context.nodes(ast.ClassDef) if node.name == summary.symbol.name), None
|
|
204
204
|
)
|
|
@@ -17,11 +17,11 @@ from sarj_python_lint.rule_base import (
|
|
|
17
17
|
is_suppressed,
|
|
18
18
|
)
|
|
19
19
|
from sarj_python_lint.rules._closed_helpers import call_matches, closed_references, direct_call, executable_body
|
|
20
|
-
from sarj_python_lint.rules._resource_provenance import ResourceProvenance
|
|
21
20
|
|
|
22
21
|
|
|
23
22
|
if TYPE_CHECKING:
|
|
24
23
|
from sarj_python_lint._file_context import PythonFileContext
|
|
24
|
+
from sarj_python_lint.rules._resource_provenance import ResourceProvenance
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
_HELPER = "def _space(match: re.Match[str]) -> str:\n full = match.group(0)\n digits = match.group(1)\n spaced = ' '.join(digits)\n return full.replace(digits, spaced)\n"
|
|
@@ -92,7 +92,7 @@ class DuplicateClosedPureHelper(Rule):
|
|
|
92
92
|
tree = context.tree
|
|
93
93
|
if context.generated or tree is None or ".group" not in context.symbol_source:
|
|
94
94
|
return []
|
|
95
|
-
provenance =
|
|
95
|
+
provenance = context.resource_provenance
|
|
96
96
|
owners: dict[str, ast.FunctionDef] = {}
|
|
97
97
|
findings: list[Diagnostic] = []
|
|
98
98
|
for function in tree.body:
|
|
@@ -103,7 +103,7 @@ class NamedRecordAtBoundaries(Rule):
|
|
|
103
103
|
source_lines = context.source_lines
|
|
104
104
|
local = _local_function_ids(tree)
|
|
105
105
|
private_class_methods = _private_class_function_ids(tree)
|
|
106
|
-
semantics =
|
|
106
|
+
semantics = context.annotation_semantics
|
|
107
107
|
imports = semantics.imports
|
|
108
108
|
fastapi = context.fastapi
|
|
109
109
|
class_shadowed_annotations = _class_shadowed_annotation_ids(tree, semantics, node_index=context.node_index)
|