sarj-python-lint 1.104.0__tar.gz → 1.108.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.104.0 → sarj_python_lint-1.108.0}/PKG-INFO +2 -2
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/pyproject.toml +2 -2
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/__init__.py +14 -3
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/__main__.py +1 -1
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_autofix.py +6 -2
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_fixes.py +3 -1
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_rule_descriptors.py +28 -1
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rule_metadata.py +16 -3
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_ast_index.py +5 -1
- sarj_python_lint-1.108.0/src/sarj_python_lint/rules/_ast_position.py +25 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_nominal_project.py +7 -1
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_registry.py +6 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_resource_provenance.py +8 -1
- sarj_python_lint-1.108.0/src/sarj_python_lint/rules/_runtime_names.py +258 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_runtime_registry.py +10 -3
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_store_writes.py +4 -8
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +1 -1
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/named_record_at_boundaries.py +1 -1
- sarj_python_lint-1.108.0/src/sarj_python_lint/rules/no_dynamic_builtins.py +100 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_hasattr.py +9 -41
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +9 -2
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +9 -2
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_redundant_local_alias.py +3 -1
- sarj_python_lint-1.108.0/src/sarj_python_lint/rules/no_shared_mutable_default.py +215 -0
- sarj_python_lint-1.108.0/src/sarj_python_lint/rules/no_sys_path_mutation.py +142 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +5 -1
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_class_row.py +11 -1
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_native_string_check.py +6 -2
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_or_pattern.py +3 -1
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_required_constructor_parameters.py +10 -1
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_str_enum.py +9 -2
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +7 -2
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_typed_mapping_get.py +41 -8
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +3 -1
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +9 -2
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +3 -1
- sarj_python_lint-1.104.0/src/sarj_python_lint/rules/_ast_position.py +0 -21
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/.gitignore +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/LICENSE +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/README.md +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_analysis_session.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_autofix_aliases.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_autofix_annotations.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_autofix_comments.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_autofix_declared_contracts.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_autofix_declared_tests.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_autofix_docs.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_autofix_enums.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_autofix_exhaustiveness.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_autofix_inert.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_autofix_parameters.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_autofix_repeated.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_autofix_security.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_autofix_sql_projection.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_autofix_tests.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_file_context.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_filesystem.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_parallel.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_prepared_sources.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_python_target.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_ratchet_cli.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_secret_names.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_source.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_version.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/application_logging.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/autofix.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/benchmark.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/cast_access.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/interpreter_argv.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/json_boundary.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/py.typed +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/ratchet.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rule_base.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/__init__.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_annotation_origins.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_ast_names.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_async_lifecycle.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_binding_inventory.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_closed_helpers.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_comment_narration.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_comments.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_copy_on_write.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_data_union_discriminator.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_declared_contracts.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_docstrings.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_exports.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_fastapi.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_first_party.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_imports.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_inert_model_annotation.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_inherited_contract.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_local_alias_fix.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_local_source.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_logging.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_mapping_shape_callbacks.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_namespace_access.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_native_namespace_capability.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_native_object_contracts.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_numeric_proof.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_opaque_contracts.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_paths.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_postgres.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_postgres_ctas.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_project_index.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_pydantic_field_contract.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_pytest.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_resolved_operation_signature.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_route_shapes.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_runtime_bindings.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_service_http_callbacks.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_set_fields.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_sql.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_sql_aggregate_identity.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_sql_explain.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_sql_policy_source.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_static_json_alias.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_store_sql.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_test_composition.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_test_provenance.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_transactional_sql.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_type_guard_symbols.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/async_executor_shutdown.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/async_subprocess_cancellation_cleanup.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/cancel_owned_task_without_join.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/delete_route_returns_no_content.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/duplicate_adjacent_exception_handler.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/duplicate_closed_pure_helper.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/duplicate_pytest_fixture_params.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/failed_probe_zero_threshold.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/nan_hidden_by_builtin_min.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_async_client_in_constructor.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_async_function_cache.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_before_validator_input_mutation.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_blanket_suppression.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_broad_keyword_capture.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_conflicting_pydantic_alias_validation.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_contradictory_type_guard.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_create_verb_in_post_path.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_custom_control_flow_exception.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_defaulted_environment_setting.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_discarded_tagged_outcome.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_discarded_validation_result.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_dual_shape_model_field_reader.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_duplicate_field_validator_body.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_exception_text_in_500_detail.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_fixed_sleep_in_loop.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_folded_bad_request_not_found.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_generic_json_parser.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_impossible_pydantic_field_bounds.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_input_model_mutation.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_interpreter_source_arguments.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_invalid_pydantic_bypass.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_invalid_pydantic_validator_return.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_loguru_exc_info.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_loguru_printf_format.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_mocked_pydantic_value_object.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_mutating_container_transform.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_mutating_input_with_result.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_partial_type_is.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_recording_store.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_redundant_attribute_unpacking.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_redundant_sql_alias.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_select_star.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_shallow_record_type_guard.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_slash_collection_root_under_prefix.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_test_comments.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_test_method_grafting.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_unknown_pydantic_validator_field.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_unused_copy_result.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/no_work_verb_get_route.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_application_model_joins.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_bulk_upsert.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_declarative_batch_validation.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_direct_import_module.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_discriminated_model_union.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_grouped_settings.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_optional_composite.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_precise_object_contract.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_psycopg_executemany.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_pydantic_model_assertion.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_pytest_dependency_fixtures.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_pytest_fixture_contract.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_runtime_validation.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_typed_cli.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_typed_settings_field.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/pytest_fixture_returns_closed_resource.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/redundant_test_constructor_forwarder.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/repeated_unimplemented_test_contract.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/require_constrained_api_integer.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/require_exp_on_jwt_decode.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/require_injectable_retry_sleep.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/require_precise_factory_signature.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/require_pydantic_for_mapping_shape.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/service_singleton_delegates_to_bulk.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/stepdown.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/store_field_update_reuses_upsert.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/store_insert_requires_explicit_conflict_policy.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/store_mutation_command_fanout.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/test_without_explicit_oracle.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/unused_test_factory_option.py +0 -0
- {sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/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.
|
|
3
|
+
Version: 1.108.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/
|
|
@@ -19,7 +19,7 @@ Classifier: Topic :: Software Development :: Quality Assurance
|
|
|
19
19
|
Requires-Python: >=3.14
|
|
20
20
|
Requires-Dist: packaging==26.3
|
|
21
21
|
Requires-Dist: ruff>=0.17.2
|
|
22
|
-
Requires-Dist: sarj-rule-contracts==0.6.
|
|
22
|
+
Requires-Dist: sarj-rule-contracts==0.6.1
|
|
23
23
|
Requires-Dist: sqlglot==30.24.0
|
|
24
24
|
Requires-Dist: typer==0.27.3
|
|
25
25
|
Description-Content-Type: text/markdown
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sarj-python-lint"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.108.0"
|
|
4
4
|
description = "Custom Python lint rules — AST-based, pre-commit-friendly, hypermodern defaults"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{ name = "sarj-ai" }]
|
|
@@ -15,7 +15,7 @@ classifiers = [
|
|
|
15
15
|
"Programming Language :: Python :: 3.14",
|
|
16
16
|
"Topic :: Software Development :: Quality Assurance",
|
|
17
17
|
]
|
|
18
|
-
dependencies = ["sarj-rule-contracts==0.6.
|
|
18
|
+
dependencies = ["sarj-rule-contracts==0.6.1", "packaging==26.3", "ruff>=0.17.2", "sqlglot==30.24.0", "typer==0.27.3"]
|
|
19
19
|
|
|
20
20
|
[project.scripts]
|
|
21
21
|
sarj-python-lint = "sarj_python_lint.__main__:main"
|
|
@@ -20,13 +20,24 @@ def __getattr__(name: str) -> object:
|
|
|
20
20
|
raise AttributeError(msg)
|
|
21
21
|
from sarj_python_lint._analysis_session import AnalysisSession as _AnalysisSession # ruff: ignore[import-outside-top-level] -- lightweight metadata imports do not need semantic rules.
|
|
22
22
|
|
|
23
|
-
globals(
|
|
23
|
+
globals( # sarj-noqa: SARJ557 -- Preserve the lazy public module namespace and historical star-import exports.
|
|
24
|
+
)["AnalysisSession"] = _AnalysisSession
|
|
24
25
|
if name == "__all__":
|
|
25
26
|
# Star imports previously exposed the complete post-session public namespace.
|
|
26
27
|
# Discover it on demand instead of freezing a narrower list of exports.
|
|
27
|
-
return tuple(
|
|
28
|
+
return tuple(
|
|
29
|
+
public
|
|
30
|
+
for public in globals( # sarj-noqa: SARJ557 -- Preserve the lazy public module namespace and historical star-import exports.
|
|
31
|
+
)
|
|
32
|
+
if not public.startswith("_")
|
|
33
|
+
)
|
|
28
34
|
return _AnalysisSession
|
|
29
35
|
|
|
30
36
|
|
|
31
37
|
def __dir__() -> list[str]:
|
|
32
|
-
return sorted(
|
|
38
|
+
return sorted(
|
|
39
|
+
set(
|
|
40
|
+
globals( # sarj-noqa: SARJ557 -- Preserve the lazy public module namespace and historical star-import exports.
|
|
41
|
+
)
|
|
42
|
+
).union({"AnalysisSession"})
|
|
43
|
+
)
|
|
@@ -103,7 +103,7 @@ def _python_files(p: Path) -> list[Path]:
|
|
|
103
103
|
for directory, directories, filenames in p.walk():
|
|
104
104
|
directories[:] = [name for name in directories if name not in SKIP_DIR_NAMES]
|
|
105
105
|
for name in filenames:
|
|
106
|
-
if not fnmatch(name, "*.py"):
|
|
106
|
+
if not fnmatch(name, "*.py") and not fnmatch(name, "*.pyi"):
|
|
107
107
|
continue
|
|
108
108
|
child = directory / name
|
|
109
109
|
if child.is_file():
|
|
@@ -514,7 +514,9 @@ def _repeated_fix(source: _Source, diagnostic: Diagnostic) -> list[TextEdit]:
|
|
|
514
514
|
def _statement_pairs(context: PythonFileContext) -> Iterator[tuple[ast.stmt, ast.stmt]]:
|
|
515
515
|
for owner in context.nodes(ast.AST):
|
|
516
516
|
for field in ("body", "orelse", "finalbody"):
|
|
517
|
-
value: object = getattr(
|
|
517
|
+
value: object = getattr( # sarj-noqa: SARJ557 -- Inspect optional statement-list fields across heterogeneous AST node types.
|
|
518
|
+
owner, field, None
|
|
519
|
+
)
|
|
518
520
|
if object_list(value):
|
|
519
521
|
statements = [item for item in value if isinstance(item, ast.stmt)]
|
|
520
522
|
yield from pairwise(statements)
|
|
@@ -1399,7 +1401,9 @@ def fix_source(path: Path, source: str, *, rule_ids: Sequence[str] | None = None
|
|
|
1399
1401
|
# Batch independent candidates; overlapping candidates get fresh offsets on the next pass.
|
|
1400
1402
|
selected_pass = _coherent_edits(candidates)
|
|
1401
1403
|
updated = apply_edits(current, selected_pass.edits)
|
|
1402
|
-
compile(
|
|
1404
|
+
compile( # sarj-noqa: SARJ557 -- Compile proposed fixes to reject invalid scopes without executing them.
|
|
1405
|
+
updated, str(path), "exec", dont_inherit=True
|
|
1406
|
+
)
|
|
1403
1407
|
if updated == current:
|
|
1404
1408
|
return current
|
|
1405
1409
|
if passes == _MAX_FIX_PASSES:
|
|
@@ -65,5 +65,7 @@ def apply_fixes(source: str, fixes: Sequence[Fix]) -> str:
|
|
|
65
65
|
result.append(raw[previous:])
|
|
66
66
|
fixed = b"".join(result).decode("utf-8")
|
|
67
67
|
tree = ast.parse(fixed)
|
|
68
|
-
compile(
|
|
68
|
+
compile( # sarj-noqa: SARJ557 -- Reject compiler-invalid fixes without executing the generated code object.
|
|
69
|
+
tree, "<native-fix>", "exec"
|
|
70
|
+
)
|
|
69
71
|
return prefix + fixed
|
{sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/_rule_descriptors.py
RENAMED
|
@@ -8,6 +8,33 @@ from sarj_python_lint.rule_metadata import RuleDescriptor
|
|
|
8
8
|
|
|
9
9
|
SCHEMA_VERSION = 1
|
|
10
10
|
DESCRIPTORS: tuple[RuleDescriptor, ...] = (
|
|
11
|
+
RuleDescriptor(
|
|
12
|
+
rule_id=RuleId("no-shared-mutable-default"),
|
|
13
|
+
module="sarj_python_lint.rules.no_shared_mutable_default",
|
|
14
|
+
class_name="NoSharedMutableDefault",
|
|
15
|
+
code="SARJ559",
|
|
16
|
+
description="Do not share mutable function defaults through aliases or read-only annotations.",
|
|
17
|
+
aliases=(),
|
|
18
|
+
enabled_by_default=True,
|
|
19
|
+
),
|
|
20
|
+
RuleDescriptor(
|
|
21
|
+
rule_id=RuleId("no-sys-path-mutation"),
|
|
22
|
+
module="sarj_python_lint.rules.no_sys_path_mutation",
|
|
23
|
+
class_name="NoSysPathMutation",
|
|
24
|
+
code="SARJ558",
|
|
25
|
+
description="Do not mutate the interpreter import search path.",
|
|
26
|
+
aliases=(),
|
|
27
|
+
enabled_by_default=True,
|
|
28
|
+
),
|
|
29
|
+
RuleDescriptor(
|
|
30
|
+
rule_id=RuleId("no-dynamic-builtins"),
|
|
31
|
+
module="sarj_python_lint.rules.no_dynamic_builtins",
|
|
32
|
+
class_name="NoDynamicBuiltins",
|
|
33
|
+
code="SARJ557",
|
|
34
|
+
description="Use explicit typed state instead of dynamic Python builtin access.",
|
|
35
|
+
aliases=(),
|
|
36
|
+
enabled_by_default=True,
|
|
37
|
+
),
|
|
11
38
|
RuleDescriptor(
|
|
12
39
|
rule_id=RuleId("service-singleton-delegates-to-bulk"),
|
|
13
40
|
module="sarj_python_lint.rules.service_singleton_delegates_to_bulk",
|
|
@@ -337,7 +364,7 @@ DESCRIPTORS: tuple[RuleDescriptor, ...] = (
|
|
|
337
364
|
module="sarj_python_lint.rules.no_hasattr",
|
|
338
365
|
class_name="NoHasattr",
|
|
339
366
|
code="SARJ499",
|
|
340
|
-
description="
|
|
367
|
+
description="Do not probe attributes with the builtin hasattr.",
|
|
341
368
|
aliases=(),
|
|
342
369
|
enabled_by_default=True,
|
|
343
370
|
),
|
|
@@ -53,11 +53,19 @@ def is_alias_tuple(value: object) -> TypeIs[tuple[str, ...]]:
|
|
|
53
53
|
|
|
54
54
|
def load_descriptors() -> tuple[RuleDescriptor, ...]:
|
|
55
55
|
module = import_module("sarj_python_lint._rule_descriptors")
|
|
56
|
-
version: object =
|
|
56
|
+
version: object = (
|
|
57
|
+
getattr( # sarj-noqa: SARJ557 -- Validate imported plugin metadata before trusting its declared rule contract.
|
|
58
|
+
module, "SCHEMA_VERSION", None
|
|
59
|
+
)
|
|
60
|
+
)
|
|
57
61
|
if type(version) is not int or version != DESCRIPTOR_SCHEMA_VERSION:
|
|
58
62
|
msg = "unsupported Python rule descriptor schema"
|
|
59
63
|
raise ValueError(msg)
|
|
60
|
-
value: object =
|
|
64
|
+
value: object = (
|
|
65
|
+
getattr( # sarj-noqa: SARJ557 -- Validate imported plugin metadata before trusting its declared rule contract.
|
|
66
|
+
module, "DESCRIPTORS", None
|
|
67
|
+
)
|
|
68
|
+
)
|
|
61
69
|
if not _object_tuple(value):
|
|
62
70
|
msg = "Python rule descriptors must be a tuple"
|
|
63
71
|
raise TypeError(msg)
|
|
@@ -102,7 +110,12 @@ def _authored_descriptor(rule_id: RuleId, rule: type[Rule]) -> RuleDescriptor:
|
|
|
102
110
|
msg = f"{rule_id}: instance metadata differs from class metadata"
|
|
103
111
|
raise ValueError(msg)
|
|
104
112
|
module = import_module(rule.__module__)
|
|
105
|
-
if
|
|
113
|
+
if (
|
|
114
|
+
getattr( # sarj-noqa: SARJ557 -- Validate imported plugin metadata before trusting its declared rule contract.
|
|
115
|
+
module, rule.__name__, None
|
|
116
|
+
)
|
|
117
|
+
is not rule
|
|
118
|
+
):
|
|
106
119
|
msg = f"{rule_id}: rule class is not importable from its declared module"
|
|
107
120
|
raise ValueError(msg)
|
|
108
121
|
return RuleDescriptor(
|
{sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_ast_index.py
RENAMED
|
@@ -47,7 +47,11 @@ def object_list(value: object) -> TypeIs[list[object]]: # sarj-noqa: SARJ528 --
|
|
|
47
47
|
def children(node: ast.AST) -> list[ast.AST]:
|
|
48
48
|
out: list[ast.AST] = []
|
|
49
49
|
for name in node._fields:
|
|
50
|
-
value: object =
|
|
50
|
+
value: object = (
|
|
51
|
+
getattr( # sarj-noqa: SARJ557 -- Preserve the profiled AST child traversal and missing-field behavior.
|
|
52
|
+
node, name, None
|
|
53
|
+
)
|
|
54
|
+
)
|
|
51
55
|
if object_list(value):
|
|
52
56
|
out += [item for item in value if isinstance(item, _AST)]
|
|
53
57
|
elif isinstance(value, _AST):
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
import ast
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass(frozen=True, order=True, slots=True)
|
|
12
|
+
class AstPosition:
|
|
13
|
+
line: int
|
|
14
|
+
column: int
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def ast_position(node: ast.AST, *, missing: int) -> AstPosition:
|
|
18
|
+
return AstPosition(
|
|
19
|
+
line=getattr( # sarj-noqa: SARJ557 -- Generic AST markers may omit source locations; preserve the caller fallback.
|
|
20
|
+
node, "lineno", missing
|
|
21
|
+
),
|
|
22
|
+
column=getattr( # sarj-noqa: SARJ557 -- Generic AST markers may omit source locations; preserve the caller fallback.
|
|
23
|
+
node, "col_offset", missing
|
|
24
|
+
),
|
|
25
|
+
)
|
{sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_nominal_project.py
RENAMED
|
@@ -19,6 +19,8 @@ from sarj_python_lint.rules._paths import is_generated
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
if TYPE_CHECKING:
|
|
22
|
+
from typing import Never
|
|
23
|
+
|
|
22
24
|
from sarj_python_lint.rules._first_party import FirstPartyFacts
|
|
23
25
|
|
|
24
26
|
|
|
@@ -239,10 +241,14 @@ def _patterns(value: object) -> tuple[str, ...] | None:
|
|
|
239
241
|
return tuple(item for item in value if isinstance(item, str))
|
|
240
242
|
|
|
241
243
|
|
|
244
|
+
def _raise_walk_error(error: OSError) -> Never:
|
|
245
|
+
raise error
|
|
246
|
+
|
|
247
|
+
|
|
242
248
|
def _files(root: Path, pattern: str) -> list[Path]:
|
|
243
249
|
found: list[Path] = []
|
|
244
250
|
try:
|
|
245
|
-
for count, (directory, directories, filenames) in enumerate(root.walk()):
|
|
251
|
+
for count, (directory, directories, filenames) in enumerate(root.walk(on_error=_raise_walk_error)):
|
|
246
252
|
if count >= _MAX_DIRECTORIES or len(found) >= _MAX_FILES:
|
|
247
253
|
# A partial inventory cannot establish uniqueness.
|
|
248
254
|
return []
|
{sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_registry.py
RENAMED
|
@@ -240,6 +240,7 @@ from sarj_python_lint.rules.no_custom_control_flow_exception import NoCustomCont
|
|
|
240
240
|
from sarj_python_lint.rules.no_defaulted_environment_setting import NoDefaultedEnvironmentSetting
|
|
241
241
|
from sarj_python_lint.rules.no_discarded_tagged_outcome import NoDiscardedTaggedOutcome
|
|
242
242
|
from sarj_python_lint.rules.no_duplicate_field_validator_body import NoDuplicateFieldValidatorBody
|
|
243
|
+
from sarj_python_lint.rules.no_dynamic_builtins import NoDynamicBuiltins
|
|
243
244
|
from sarj_python_lint.rules.no_exception_text_in_500_detail import NoExceptionTextIn500Detail
|
|
244
245
|
from sarj_python_lint.rules.no_folded_bad_request_not_found import NoFoldedBadRequestNotFound
|
|
245
246
|
from sarj_python_lint.rules.no_hasattr import NoHasattr
|
|
@@ -251,7 +252,9 @@ from sarj_python_lint.rules.no_recording_store import NoRecordingStore
|
|
|
251
252
|
from sarj_python_lint.rules.no_redundant_local_alias import NoRedundantLocalAlias
|
|
252
253
|
from sarj_python_lint.rules.no_redundant_sql_alias import NoRedundantSqlAlias
|
|
253
254
|
from sarj_python_lint.rules.no_shallow_record_type_guard import NoShallowRecordTypeGuard
|
|
255
|
+
from sarj_python_lint.rules.no_shared_mutable_default import NoSharedMutableDefault
|
|
254
256
|
from sarj_python_lint.rules.no_slash_collection_root_under_prefix import NoSlashCollectionRootUnderPrefix
|
|
257
|
+
from sarj_python_lint.rules.no_sys_path_mutation import NoSysPathMutation
|
|
255
258
|
from sarj_python_lint.rules.no_unknown_pydantic_validator_field import NoUnknownPydanticValidatorField
|
|
256
259
|
from sarj_python_lint.rules.no_work_verb_get_route import NoWorkVerbGetRoute
|
|
257
260
|
from sarj_python_lint.rules.prefer_application_model_joins import PreferApplicationModelJoins
|
|
@@ -283,6 +286,9 @@ from sarj_python_lint.rules.test_without_explicit_oracle import NoExplicitTestOr
|
|
|
283
286
|
|
|
284
287
|
_AUTHORING_REGISTRY: Mapping[str, type[Rule]] = MappingProxyType(
|
|
285
288
|
{
|
|
289
|
+
NoSharedMutableDefault.id: NoSharedMutableDefault,
|
|
290
|
+
NoSysPathMutation.id: NoSysPathMutation,
|
|
291
|
+
NoDynamicBuiltins.id: NoDynamicBuiltins,
|
|
286
292
|
ServiceSingletonDelegatesToBulk.id: ServiceSingletonDelegatesToBulk,
|
|
287
293
|
NoAsyncClientInConstructor.id: NoAsyncClientInConstructor,
|
|
288
294
|
NoDiscardedTaggedOutcome.id: NoDiscardedTaggedOutcome,
|
|
@@ -338,7 +338,14 @@ class ResourceProvenance:
|
|
|
338
338
|
return None
|
|
339
339
|
if not isinstance(self.parents.get(statement), ast.Module | ast.FunctionDef | ast.AsyncFunctionDef):
|
|
340
340
|
return None
|
|
341
|
-
return
|
|
341
|
+
return (
|
|
342
|
+
statement.value
|
|
343
|
+
if statement.lineno
|
|
344
|
+
< getattr( # sarj-noqa: SARJ557 -- Order heterogeneous AST markers while preserving the missing-location fallback.
|
|
345
|
+
at, "lineno", 0
|
|
346
|
+
)
|
|
347
|
+
else None
|
|
348
|
+
)
|
|
342
349
|
|
|
343
350
|
def async_function(self, value: ast.expr, at: ast.AST) -> ast.AsyncFunctionDef | None:
|
|
344
351
|
if self.dynamic_namespace:
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
import keyword
|
|
6
|
+
from typing import TYPE_CHECKING, final
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from collections.abc import Iterable
|
|
11
|
+
|
|
12
|
+
from sarj_python_lint._file_context import PythonFileContext
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
_FUNCTION_SCOPES = (
|
|
16
|
+
ast.FunctionDef,
|
|
17
|
+
ast.AsyncFunctionDef,
|
|
18
|
+
ast.Lambda,
|
|
19
|
+
ast.ListComp,
|
|
20
|
+
ast.SetComp,
|
|
21
|
+
ast.DictComp,
|
|
22
|
+
ast.GeneratorExp,
|
|
23
|
+
)
|
|
24
|
+
_NATIVE_NAMES = frozenset(
|
|
25
|
+
{
|
|
26
|
+
"__import__",
|
|
27
|
+
"bool",
|
|
28
|
+
"bytearray",
|
|
29
|
+
"bytes",
|
|
30
|
+
"complex",
|
|
31
|
+
"compile",
|
|
32
|
+
"delattr",
|
|
33
|
+
"dict",
|
|
34
|
+
"float",
|
|
35
|
+
"frozenset",
|
|
36
|
+
"getattr",
|
|
37
|
+
"globals",
|
|
38
|
+
"hasattr",
|
|
39
|
+
"int",
|
|
40
|
+
"list",
|
|
41
|
+
"locals",
|
|
42
|
+
"object",
|
|
43
|
+
"range",
|
|
44
|
+
"set",
|
|
45
|
+
"setattr",
|
|
46
|
+
"str",
|
|
47
|
+
"tuple",
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
_RUFF_BANNED_API = frozenset({"locals", "globals", "compile", "__import__", "getattr", "hasattr", "delattr"})
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass(frozen=True, slots=True)
|
|
55
|
+
class BuiltinReference:
|
|
56
|
+
node: ast.expr | ast.alias
|
|
57
|
+
name: str
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@final
|
|
61
|
+
class RuntimeNames:
|
|
62
|
+
def __init__(self, context: PythonFileContext) -> None:
|
|
63
|
+
self.context = context
|
|
64
|
+
self.inventory = context.binding_inventory
|
|
65
|
+
|
|
66
|
+
def builtin(self, node: ast.Name) -> bool:
|
|
67
|
+
return not self.inventory.wildcard and self._binding_scope(node.id, node) is None
|
|
68
|
+
|
|
69
|
+
def qualified(self, expression: ast.expr) -> str | None:
|
|
70
|
+
if self.inventory.wildcard:
|
|
71
|
+
return None
|
|
72
|
+
return self._qualified(expression, frozenset(), assignments=True)
|
|
73
|
+
|
|
74
|
+
def imported_qualified(self, expression: ast.expr) -> str | None:
|
|
75
|
+
if self.inventory.wildcard:
|
|
76
|
+
return None
|
|
77
|
+
return self._qualified(expression, frozenset(), assignments=False)
|
|
78
|
+
|
|
79
|
+
def assigned_value(self, node: ast.Name) -> ast.expr | None:
|
|
80
|
+
scope = self._binding_scope(node.id, node)
|
|
81
|
+
declarations = self.inventory.bindings.get(scope, {}).get(node.id, ())
|
|
82
|
+
stable = tuple(item for item in declarations if not self._inplace_target(item))
|
|
83
|
+
if len(stable) != 1 or not isinstance(stable[0], ast.Name):
|
|
84
|
+
return None
|
|
85
|
+
return self._assignment(stable[0])
|
|
86
|
+
|
|
87
|
+
def banned_references(self, names: frozenset[str]) -> list[BuiltinReference]:
|
|
88
|
+
references = [
|
|
89
|
+
reference
|
|
90
|
+
for node in self.context.nodes(ast.Name, ast.Attribute)
|
|
91
|
+
if (reference := self._banned_reference(node, names)) is not None
|
|
92
|
+
]
|
|
93
|
+
if imported := names.intersection({"exec", "eval"}):
|
|
94
|
+
references.extend(
|
|
95
|
+
BuiltinReference(alias, alias.name)
|
|
96
|
+
for statement in self.context.nodes(ast.ImportFrom)
|
|
97
|
+
if statement.level == 0 and statement.module == "builtins"
|
|
98
|
+
for alias in statement.names
|
|
99
|
+
if alias.name in imported
|
|
100
|
+
)
|
|
101
|
+
return sorted(references, key=lambda item: (item.node.lineno, item.node.col_offset))
|
|
102
|
+
|
|
103
|
+
def _banned_reference(self, node: ast.Name | ast.Attribute, names: frozenset[str]) -> BuiltinReference | None:
|
|
104
|
+
if not isinstance(node.ctx, ast.Load):
|
|
105
|
+
return None
|
|
106
|
+
if isinstance(node, ast.Name):
|
|
107
|
+
if node.id not in names or not self.builtin(node):
|
|
108
|
+
return None
|
|
109
|
+
name = node.id
|
|
110
|
+
direct_import = False
|
|
111
|
+
else:
|
|
112
|
+
qualified = self.qualified(node)
|
|
113
|
+
if qualified is None or not qualified.startswith("builtins."):
|
|
114
|
+
return None
|
|
115
|
+
name = qualified.removeprefix("builtins.")
|
|
116
|
+
if name not in names:
|
|
117
|
+
return None
|
|
118
|
+
direct_import = self._direct_builtin_module(node.value)
|
|
119
|
+
if self._native_owner(node, name, direct_import=direct_import):
|
|
120
|
+
return None
|
|
121
|
+
return BuiltinReference(node, name)
|
|
122
|
+
|
|
123
|
+
def _direct_builtin_module(self, node: ast.expr) -> bool:
|
|
124
|
+
if not isinstance(node, ast.Name):
|
|
125
|
+
return False
|
|
126
|
+
scope = self._binding_scope(node.id, node)
|
|
127
|
+
declarations = self.inventory.bindings.get(scope, {}).get(node.id, ())
|
|
128
|
+
return bool(declarations) and all(
|
|
129
|
+
isinstance(item, ast.alias)
|
|
130
|
+
and isinstance(self.context.parents.get(item), ast.Import)
|
|
131
|
+
and item.name == "builtins"
|
|
132
|
+
for item in declarations
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
def _native_owner(self, node: ast.expr, name: str, *, direct_import: bool) -> bool:
|
|
136
|
+
if direct_import and name in _RUFF_BANNED_API:
|
|
137
|
+
return True
|
|
138
|
+
if name == "eval" and (isinstance(node, ast.Name) or direct_import):
|
|
139
|
+
return True
|
|
140
|
+
parent = self.context.parents.get(node)
|
|
141
|
+
if not isinstance(parent, ast.Call) or parent.func is not node:
|
|
142
|
+
return False
|
|
143
|
+
if name in {"exec", "breakpoint"}:
|
|
144
|
+
return isinstance(node, ast.Name) or direct_import
|
|
145
|
+
if isinstance(node, ast.Attribute) or parent.keywords:
|
|
146
|
+
return False
|
|
147
|
+
match parent.args:
|
|
148
|
+
case [receiver, ast.Constant(value=str() as value)]:
|
|
149
|
+
if name == "getattr" and isinstance(receiver, ast.Starred):
|
|
150
|
+
return False
|
|
151
|
+
case _:
|
|
152
|
+
return False
|
|
153
|
+
if name == "hasattr":
|
|
154
|
+
return value == "__call__"
|
|
155
|
+
if name != "getattr":
|
|
156
|
+
return False
|
|
157
|
+
mangled = value.startswith("__") and not value.endswith("__")
|
|
158
|
+
return value.isidentifier() and not keyword.iskeyword(value) and not mangled
|
|
159
|
+
|
|
160
|
+
def _binding_scope(self, name: str, at: ast.AST) -> ast.AST | None:
|
|
161
|
+
scope = self._scope(at)
|
|
162
|
+
skip_classes = False
|
|
163
|
+
while scope is not None:
|
|
164
|
+
if isinstance(scope, ast.ClassDef) and skip_classes:
|
|
165
|
+
scope = self._scope(scope)
|
|
166
|
+
continue
|
|
167
|
+
declarations = self.inventory.bindings.get(scope, {}).get(name, ())
|
|
168
|
+
globals_here = any(isinstance(item, ast.Global) for item in declarations)
|
|
169
|
+
if globals_here and scope is not self.context.tree:
|
|
170
|
+
if _declares_value(declarations):
|
|
171
|
+
return scope
|
|
172
|
+
scope = self.context.tree
|
|
173
|
+
continue
|
|
174
|
+
if _declares_value(declarations) or name in _type_parameters(scope):
|
|
175
|
+
return scope
|
|
176
|
+
skip_classes |= isinstance(scope, _FUNCTION_SCOPES)
|
|
177
|
+
scope = self._scope(scope)
|
|
178
|
+
return None
|
|
179
|
+
|
|
180
|
+
def _scope(self, node: ast.AST) -> ast.AST | None:
|
|
181
|
+
original = node
|
|
182
|
+
parent = self.context.parents.get(node)
|
|
183
|
+
while parent is not None:
|
|
184
|
+
if isinstance(parent, ast.TypeAlias):
|
|
185
|
+
return parent
|
|
186
|
+
if isinstance(parent, ast.comprehension) and parent.iter is node:
|
|
187
|
+
owner = self.context.parents.get(parent)
|
|
188
|
+
if (
|
|
189
|
+
isinstance(owner, ast.ListComp | ast.SetComp | ast.DictComp | ast.GeneratorExp)
|
|
190
|
+
and owner.generators[0] is parent
|
|
191
|
+
):
|
|
192
|
+
return self._scope(owner)
|
|
193
|
+
if isinstance(parent, (ast.Module, ast.ClassDef, *_FUNCTION_SCOPES)):
|
|
194
|
+
break
|
|
195
|
+
node, parent = parent, self.context.parents.get(parent)
|
|
196
|
+
return self.inventory.scope(original)
|
|
197
|
+
|
|
198
|
+
def _qualified(self, expression: ast.expr, seen: frozenset[ast.AST], *, assignments: bool) -> str | None:
|
|
199
|
+
if expression in seen:
|
|
200
|
+
return None
|
|
201
|
+
seen |= {expression}
|
|
202
|
+
if isinstance(expression, ast.Attribute):
|
|
203
|
+
base = self._qualified(expression.value, seen, assignments=assignments)
|
|
204
|
+
return None if base is None else f"{base}.{expression.attr}"
|
|
205
|
+
if not isinstance(expression, ast.Name):
|
|
206
|
+
return None
|
|
207
|
+
scope = self._binding_scope(expression.id, expression)
|
|
208
|
+
if scope is None:
|
|
209
|
+
return f"builtins.{expression.id}" if expression.id in _NATIVE_NAMES else None
|
|
210
|
+
declarations = self.inventory.bindings.get(scope, {}).get(expression.id, ())
|
|
211
|
+
declarations = tuple(item for item in declarations if not self._inplace_target(item))
|
|
212
|
+
if not declarations:
|
|
213
|
+
return None
|
|
214
|
+
origins = {self._declaration_origin(item, seen, assignments=assignments) for item in declarations}
|
|
215
|
+
if len(origins) != 1:
|
|
216
|
+
return None
|
|
217
|
+
return next(iter(origins))
|
|
218
|
+
|
|
219
|
+
def _declaration_origin(self, node: ast.AST, seen: frozenset[ast.AST], *, assignments: bool) -> str | None:
|
|
220
|
+
if node in seen:
|
|
221
|
+
return None
|
|
222
|
+
parent = self.context.parents.get(node)
|
|
223
|
+
if isinstance(node, ast.alias):
|
|
224
|
+
if isinstance(parent, ast.Import):
|
|
225
|
+
return node.name if node.asname else node.name.partition(".")[0]
|
|
226
|
+
if isinstance(parent, ast.ImportFrom) and parent.level == 0 and parent.module is not None:
|
|
227
|
+
return f"{parent.module}.{node.name}"
|
|
228
|
+
if assignments and isinstance(node, ast.Name) and (value := self._assignment(node)) is not None:
|
|
229
|
+
return self._qualified(value, seen | {node}, assignments=assignments)
|
|
230
|
+
return None
|
|
231
|
+
|
|
232
|
+
def _assignment(self, node: ast.Name) -> ast.expr | None:
|
|
233
|
+
parent = self.context.parents.get(node)
|
|
234
|
+
if isinstance(parent, ast.Assign) and node in parent.targets:
|
|
235
|
+
return parent.value
|
|
236
|
+
if isinstance(parent, ast.AnnAssign) and parent.target is node:
|
|
237
|
+
return parent.value
|
|
238
|
+
if isinstance(parent, ast.NamedExpr) and parent.target is node:
|
|
239
|
+
return parent.value
|
|
240
|
+
return None
|
|
241
|
+
|
|
242
|
+
def _inplace_target(self, node: ast.AST) -> bool:
|
|
243
|
+
parent = self.context.parents.get(node)
|
|
244
|
+
return isinstance(parent, ast.AugAssign) and parent.target is node
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def _declares_value(declarations: Iterable[ast.AST]) -> bool:
|
|
248
|
+
return any(not isinstance(item, ast.Global) for item in declarations)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def _type_parameters(scope: ast.AST) -> frozenset[str]:
|
|
252
|
+
if isinstance(scope, ast.FunctionDef | ast.AsyncFunctionDef | ast.ClassDef | ast.TypeAlias):
|
|
253
|
+
return frozenset(
|
|
254
|
+
parameter.name
|
|
255
|
+
for parameter in scope.type_params
|
|
256
|
+
if isinstance(parameter, ast.TypeVar | ast.ParamSpec | ast.TypeVarTuple)
|
|
257
|
+
)
|
|
258
|
+
return frozenset()
|
|
@@ -76,7 +76,9 @@ def _constructor_hooks(rule: type[Rule]) -> _ConstructorHooks | None:
|
|
|
76
76
|
or not _is_constructor_hook(metaclass_call)
|
|
77
77
|
):
|
|
78
78
|
return None
|
|
79
|
-
code: object = getattr(
|
|
79
|
+
code: object = getattr( # sarj-noqa: SARJ557 -- Validate dynamically imported plugin classes and optional native constructor metadata.
|
|
80
|
+
initializer, "__code__", None
|
|
81
|
+
)
|
|
80
82
|
if code is not None and not isinstance(code, CodeType):
|
|
81
83
|
return None
|
|
82
84
|
return _ConstructorHooks(initializer, code, allocator, metaclass_call)
|
|
@@ -143,7 +145,9 @@ class _RegistryState:
|
|
|
143
145
|
if entry.module in sys.modules:
|
|
144
146
|
self.external_modules.add(entry.module)
|
|
145
147
|
module = import_module(entry.module)
|
|
146
|
-
value: object = getattr(
|
|
148
|
+
value: object = getattr( # sarj-noqa: SARJ557 -- Validate dynamically imported plugin classes and optional native constructor metadata.
|
|
149
|
+
module, entry.class_name, None
|
|
150
|
+
)
|
|
147
151
|
if not isinstance(value, type) or not issubclass(value, Rule):
|
|
148
152
|
msg = f"{entry.rule_id}: descriptor does not resolve to a Rule class"
|
|
149
153
|
raise TypeError(msg)
|
|
@@ -201,7 +205,10 @@ class _RegistryState:
|
|
|
201
205
|
module is None
|
|
202
206
|
or rule is None
|
|
203
207
|
or observed is None
|
|
204
|
-
or getattr(
|
|
208
|
+
or getattr( # sarj-noqa: SARJ557 -- Validate dynamically imported plugin classes and optional native constructor metadata.
|
|
209
|
+
module, entry.class_name, None
|
|
210
|
+
)
|
|
211
|
+
is not rule
|
|
205
212
|
):
|
|
206
213
|
return None
|
|
207
214
|
if (
|
{sarj_python_lint-1.104.0 → sarj_python_lint-1.108.0}/src/sarj_python_lint/rules/_store_writes.py
RENAMED
|
@@ -11,6 +11,7 @@ from sqlglot.errors import SqlglotError
|
|
|
11
11
|
|
|
12
12
|
from sarj_python_lint.rules._annotation_semantics import AnnotationSemantics, bit_or_members, scope_bound_names
|
|
13
13
|
from sarj_python_lint.rules._ast_index import walk
|
|
14
|
+
from sarj_python_lint.rules._ast_position import ast_position
|
|
14
15
|
from sarj_python_lint.rules._paths import is_generated
|
|
15
16
|
from sarj_python_lint.rules._project_index import ProjectIndexSet
|
|
16
17
|
|
|
@@ -19,6 +20,7 @@ if TYPE_CHECKING:
|
|
|
19
20
|
from collections.abc import Iterable, Iterator
|
|
20
21
|
|
|
21
22
|
from sarj_python_lint._file_context import PythonFileContext
|
|
23
|
+
from sarj_python_lint.rules._ast_position import AstPosition
|
|
22
24
|
from sarj_python_lint.rules._imports import ImportIndex
|
|
23
25
|
from sarj_python_lint.rules._resource_provenance import ResourceProvenance
|
|
24
26
|
|
|
@@ -433,12 +435,6 @@ class _ReceiverOrigin:
|
|
|
433
435
|
attribute: str | None = None
|
|
434
436
|
|
|
435
437
|
|
|
436
|
-
@dataclass(frozen=True, order=True, slots=True)
|
|
437
|
-
class _SourcePosition:
|
|
438
|
-
line: int
|
|
439
|
-
column: int
|
|
440
|
-
|
|
441
|
-
|
|
442
438
|
class _ReceiverAliases:
|
|
443
439
|
def __init__(self, context: PythonFileContext) -> None:
|
|
444
440
|
self.context = context
|
|
@@ -535,8 +531,8 @@ class _ReceiverAliases:
|
|
|
535
531
|
return frozenset()
|
|
536
532
|
|
|
537
533
|
|
|
538
|
-
def _source_position(node: ast.AST) ->
|
|
539
|
-
return
|
|
534
|
+
def _source_position(node: ast.AST) -> AstPosition:
|
|
535
|
+
return ast_position(node, missing=-1)
|
|
540
536
|
|
|
541
537
|
|
|
542
538
|
class StoreOwners:
|
|
@@ -196,7 +196,7 @@ def _returns_local_router(function: ast.FunctionDef | ast.AsyncFunctionDef, call
|
|
|
196
196
|
for node in function.body
|
|
197
197
|
if isinstance(node, (ast.Assign, ast.AnnAssign))
|
|
198
198
|
for target in _assignment_targets(node)
|
|
199
|
-
if isinstance(target, ast.Name) and
|
|
199
|
+
if isinstance(target, ast.Name) and node.value is call
|
|
200
200
|
}
|
|
201
201
|
return bool(names) and any(
|
|
202
202
|
isinstance(node, ast.Return) and isinstance(node.value, ast.Name) and node.value.id in names
|
|
@@ -251,7 +251,7 @@ def _resolve_annotation(node: ast.expr | None) -> ast.expr | None:
|
|
|
251
251
|
if isinstance(node, ast.Constant) and isinstance(node.value, str):
|
|
252
252
|
try:
|
|
253
253
|
return ast.parse(node.value.strip(), mode="eval").body
|
|
254
|
-
except SyntaxError:
|
|
254
|
+
except SyntaxError, UnicodeError:
|
|
255
255
|
return None
|
|
256
256
|
return node
|
|
257
257
|
|