sarj-python-lint 1.83.0__tar.gz → 1.84.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.83.0 → sarj_python_lint-1.84.0}/PKG-INFO +1 -1
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/pyproject.toml +1 -1
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/__main__.py +3 -2
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_autofix.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_autofix_enums.py +1 -1
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_autofix_repeated.py +1 -1
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_file_context.py +11 -1
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_annotation_origins.py +43 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_annotation_semantics.py +7 -4
- sarj_python_lint-1.84.0/src/sarj_python_lint/rules/_binding_inventory.py +131 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_closed_helpers.py +1 -1
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_copy_on_write.py +29 -20
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_data_union_discriminator.py +3 -1
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_docstrings.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_fastapi.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_imports.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_mapping_shape_callbacks.py +18 -12
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_native_object_contracts.py +25 -16
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_opaque_contracts.py +22 -15
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_project_index.py +72 -60
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_prose_budget.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_registry.py +6 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_resource_provenance.py +20 -87
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_store_writes.py +8 -5
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_test_composition.py +17 -14
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +8 -5
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +14 -8
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/duplicate_closed_pure_helper.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_broad_keyword_capture.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +48 -37
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_interpreter_source_arguments.py +39 -22
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_invalid_pydantic_bypass.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +16 -10
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +15 -9
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_redundant_local_alias.py +8 -5
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_repeated_string_literal.py +8 -7
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +18 -8
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_tautological_expect.py +29 -17
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +23 -20
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/over_mocked_test.py +7 -6
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_class_row.py +14 -10
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +17 -11
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_declarative_batch_validation.py +14 -8
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_discriminated_model_union.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_library_fake.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +151 -7
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +9 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_native_string_check.py +14 -8
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +14 -11
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_or_pattern.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_pydantic_model_assertion.py +13 -10
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_required_constructor_parameters.py +10 -8
- sarj_python_lint-1.84.0/src/sarj_python_lint/rules/prefer_runtime_validation.py +97 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_str_enum.py +45 -30
- sarj_python_lint-1.84.0/src/sarj_python_lint/rules/prefer_typed_cli.py +219 -0
- sarj_python_lint-1.84.0/src/sarj_python_lint/rules/prefer_typed_mapping_get.py +189 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +9 -6
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +22 -19
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/redundant_docstring.py +8 -7
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +8 -5
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +30 -21
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/require_port_for_service.py +23 -16
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +16 -10
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/require_pydantic_for_mapping_shape.py +18 -20
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +8 -5
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/restated_test_docstring.py +16 -12
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/stepdown.py +8 -5
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +29 -17
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +7 -4
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +30 -24
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/unused_mock_setup.py +19 -5
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/.gitignore +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/LICENSE +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/README.md +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/__init__.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_analysis_session.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_autofix_aliases.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_autofix_annotations.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_autofix_comments.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_autofix_declared_contracts.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_autofix_declared_tests.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_autofix_docs.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_autofix_exhaustiveness.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_autofix_inert.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_autofix_parameters.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_autofix_security.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_autofix_sql_projection.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_autofix_tests.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_filesystem.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_fixes.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_parallel.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_python_target.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_ratchet_cli.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_secret_names.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_source.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_version.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/application_logging.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/autofix.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/benchmark.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/cast_access.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/interpreter_argv.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/json_boundary.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/py.typed +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/ratchet.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rule_base.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/__init__.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_ast_index.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_ast_names.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_ast_position.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_async_lifecycle.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_comment_narration.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_comments.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_declared_contracts.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_exports.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_first_party.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_inert_model_annotation.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_inherited_contract.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_local_alias_fix.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_local_source.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_logging.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_namespace_access.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_native_namespace_capability.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_numeric_proof.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_paths.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_pydantic_field_contract.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_pytest.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_resolved_operation_signature.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_route_shapes.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_runtime_bindings.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_service_http_callbacks.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_set_fields.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_sql.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_sql_aggregate_identity.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_sql_explain.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_sql_policy_source.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_static_json_alias.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_test_provenance.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_transactional_sql.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_type_guard_symbols.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/async_executor_shutdown.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/async_subprocess_cancellation_cleanup.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/cancel_owned_task_without_join.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/delete_route_returns_no_content.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/duplicate_adjacent_exception_handler.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/duplicate_pytest_fixture_params.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/failed_probe_zero_threshold.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/nan_hidden_by_builtin_min.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_async_function_cache.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_before_validator_input_mutation.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_blanket_suppression.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_conflicting_pydantic_alias_validation.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_contradictory_type_guard.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_create_verb_in_post_path.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_defaulted_environment_setting.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_discarded_validation_result.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_dual_shape_model_field_reader.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_duplicate_field_validator_body.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_exception_text_in_500_detail.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_fixed_sleep_in_loop.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_folded_bad_request_not_found.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_hasattr.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_impossible_pydantic_field_bounds.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_input_model_mutation.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_invalid_pydantic_validator_return.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_loguru_exc_info.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_loguru_printf_format.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_mocked_pydantic_value_object.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_mutating_container_transform.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_partial_type_is.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_select_star.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_shallow_record_type_guard.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_slash_collection_root_under_prefix.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_test_method_grafting.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_unknown_pydantic_validator_field.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_unused_copy_result.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/no_work_verb_get_route.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_bulk_upsert.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_direct_import_module.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_grouped_settings.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_precise_object_contract.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_psycopg_executemany.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_pytest_dependency_fixtures.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_typed_settings_field.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/pytest_fixture_returns_closed_resource.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/redundant_test_constructor_forwarder.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/repeated_unimplemented_test_contract.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/require_exp_on_jwt_decode.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/require_injectable_retry_sleep.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/require_precise_factory_signature.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/store_field_update_reuses_upsert.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/test_without_explicit_oracle.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/unused_test_factory_option.py +0 -0
- {sarj_python_lint-1.83.0 → sarj_python_lint-1.84.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.84.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/
|
|
@@ -187,12 +187,13 @@ _DIAGNOSTIC_PRECEDENCE = MappingProxyType(
|
|
|
187
187
|
# A proven external or nested request boundary already requires schema
|
|
188
188
|
# validation at this field read. Retain standalone shape advice when
|
|
189
189
|
# that more specific rule is unselected or locally suppressed.
|
|
190
|
-
"SARJ411": frozenset({"SARJ521"}),
|
|
190
|
+
"SARJ411": frozenset({"SARJ521", "SARJ535"}),
|
|
191
191
|
# Any-valued mappings are the stronger correctness failure. SARJ008
|
|
192
192
|
# still owns every fixed dictionary return when selected alone, while
|
|
193
193
|
# an all-rules run emits one actionable diagnostic for this overlap.
|
|
194
194
|
"SARJ447": frozenset({"SARJ008"}),
|
|
195
|
-
"SARJ450": frozenset({"SARJ521"}),
|
|
195
|
+
"SARJ450": frozenset({"SARJ521", "SARJ535"}),
|
|
196
|
+
"SARJ521": frozenset({"SARJ535"}),
|
|
196
197
|
"SARJ457": frozenset({"SARJ045"}),
|
|
197
198
|
"SARJ465": frozenset({"SARJ071"}),
|
|
198
199
|
"SARJ491": frozenset({"SARJ400"}),
|
|
@@ -993,10 +993,13 @@ def _jwt_required_sequence(required: ast.expr) -> ast.expr | None:
|
|
|
993
993
|
):
|
|
994
994
|
return None
|
|
995
995
|
elements = [*required.elts, ast.Constant(value="exp")]
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
996
|
+
match required:
|
|
997
|
+
case ast.List():
|
|
998
|
+
return ast.List(elts=elements, ctx=ast.Load())
|
|
999
|
+
case ast.Tuple():
|
|
1000
|
+
return ast.Tuple(elts=elements, ctx=ast.Load())
|
|
1001
|
+
case _:
|
|
1002
|
+
pass
|
|
1000
1003
|
return ast.Set(elts=elements)
|
|
1001
1004
|
|
|
1002
1005
|
|
|
@@ -164,7 +164,7 @@ class EnumFixes:
|
|
|
164
164
|
|
|
165
165
|
def _stable_alias(self, alias: ast.TypeAlias) -> bool:
|
|
166
166
|
if any(
|
|
167
|
-
bindings.get(alias.name.id,
|
|
167
|
+
bindings.get(alias.name.id, ()) not in {(), (alias.name,)} for bindings in self.provenance.bindings.values()
|
|
168
168
|
):
|
|
169
169
|
return False
|
|
170
170
|
if any(
|
{sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/_autofix_repeated.py
RENAMED
|
@@ -115,7 +115,7 @@ class RepeatedLiteralFixes:
|
|
|
115
115
|
|
|
116
116
|
def _stable_binding(self, binding: ast.Name, literal: ast.Constant, parent: ast.FunctionDef) -> bool:
|
|
117
117
|
return (
|
|
118
|
-
self.provenance.bindings.get(parent, {}).get(binding.id) ==
|
|
118
|
+
self.provenance.bindings.get(parent, {}).get(binding.id) == (binding,)
|
|
119
119
|
and self.provenance.binding(binding.id, literal) is binding
|
|
120
120
|
and binding.id not in self.provenance.external_bindings
|
|
121
121
|
and (binding.lineno, binding.col_offset + 1) not in self.locations
|
|
@@ -8,10 +8,12 @@ from sarj_python_lint._analysis_session import AnalysisSession
|
|
|
8
8
|
from sarj_python_lint._source import python_source_lines, symbol_prefilter_source
|
|
9
9
|
from sarj_python_lint.rules._annotation_semantics import AnnotationSemantics
|
|
10
10
|
from sarj_python_lint.rules._ast_index import NodeIndex
|
|
11
|
+
from sarj_python_lint.rules._binding_inventory import BindingInventory
|
|
11
12
|
from sarj_python_lint.rules._fastapi import FastapiIndex
|
|
12
13
|
from sarj_python_lint.rules._imports import ImportIndex
|
|
13
14
|
from sarj_python_lint.rules._namespace_access import dynamic_namespace_access
|
|
14
15
|
from sarj_python_lint.rules._paths import is_generated
|
|
16
|
+
from sarj_python_lint.rules._runtime_bindings import RuntimeBindings
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
if TYPE_CHECKING:
|
|
@@ -23,7 +25,7 @@ if TYPE_CHECKING:
|
|
|
23
25
|
from sarj_python_lint.rules._test_provenance import TestProvenance
|
|
24
26
|
|
|
25
27
|
|
|
26
|
-
@final
|
|
28
|
+
@final # ruff: ignore[too-many-public-methods] -- one file owns the lazy fact caches and their shared lifetime; splitting providers would duplicate semantic state.
|
|
27
29
|
class PythonFileContext:
|
|
28
30
|
def __init__(self, path: Path, source: str, session: AnalysisSession | None = None) -> None:
|
|
29
31
|
self.path = path
|
|
@@ -85,6 +87,14 @@ class PythonFileContext:
|
|
|
85
87
|
def parents(self) -> Mapping[ast.AST, ast.AST]:
|
|
86
88
|
return self.node_index.parents
|
|
87
89
|
|
|
90
|
+
@cached_property
|
|
91
|
+
def binding_inventory(self) -> BindingInventory:
|
|
92
|
+
return BindingInventory.from_context(self)
|
|
93
|
+
|
|
94
|
+
@cached_property
|
|
95
|
+
def runtime_bindings(self) -> RuntimeBindings:
|
|
96
|
+
return RuntimeBindings(self, self.binding_inventory.bindings)
|
|
97
|
+
|
|
88
98
|
@cached_property
|
|
89
99
|
def imports(self) -> ImportIndex:
|
|
90
100
|
return ImportIndex.from_tree(self._valid_tree())
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import ast
|
|
4
|
+
from dataclasses import dataclass
|
|
4
5
|
from typing import TYPE_CHECKING
|
|
5
6
|
|
|
6
7
|
from sarj_python_lint.rules._imports import ImportIndex
|
|
@@ -10,6 +11,15 @@ if TYPE_CHECKING:
|
|
|
10
11
|
from sarj_python_lint._file_context import PythonFileContext
|
|
11
12
|
|
|
12
13
|
|
|
14
|
+
_MAX_ALIAS_DEPTH = 32
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass(frozen=True, slots=True)
|
|
18
|
+
class ResolvedAnnotation:
|
|
19
|
+
expression: ast.expr
|
|
20
|
+
at: ast.expr
|
|
21
|
+
|
|
22
|
+
|
|
13
23
|
class AnnotationOrigins:
|
|
14
24
|
def __init__(self, context: PythonFileContext) -> None:
|
|
15
25
|
self.context = context
|
|
@@ -19,6 +29,39 @@ class AnnotationOrigins:
|
|
|
19
29
|
for node in context.nodes(ast.Import, ast.ImportFrom)
|
|
20
30
|
}
|
|
21
31
|
|
|
32
|
+
def alias_value(self, node: ast.Name, at: ast.AST) -> ast.expr | None:
|
|
33
|
+
value = self.context.annotation_semantics.aliases.get(node.id)
|
|
34
|
+
if value is None:
|
|
35
|
+
return None
|
|
36
|
+
binding = self.provenance.binding(node.id, at)
|
|
37
|
+
if not isinstance(binding, ast.Name):
|
|
38
|
+
return None
|
|
39
|
+
parent = self.context.parents.get(binding)
|
|
40
|
+
if isinstance(parent, ast.TypeAlias | ast.AnnAssign) and parent.value is value:
|
|
41
|
+
return value
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
def resolve_annotation(self, node: ast.expr, *, at: ast.expr | None = None) -> ResolvedAnnotation | None:
|
|
45
|
+
current = node
|
|
46
|
+
scope = node if at is None else at
|
|
47
|
+
seen: set[str] = set()
|
|
48
|
+
for _ in range(_MAX_ALIAS_DEPTH):
|
|
49
|
+
parsed = self.context.annotation_semantics.parse(current)
|
|
50
|
+
if parsed is None:
|
|
51
|
+
return None
|
|
52
|
+
if isinstance(parsed, ast.Name):
|
|
53
|
+
if self.shadowed(parsed.id, scope):
|
|
54
|
+
return None
|
|
55
|
+
value = self.alias_value(parsed, scope)
|
|
56
|
+
if value is not None:
|
|
57
|
+
if parsed.id in seen:
|
|
58
|
+
return None
|
|
59
|
+
seen.add(parsed.id)
|
|
60
|
+
current = scope = value
|
|
61
|
+
continue
|
|
62
|
+
return ResolvedAnnotation(parsed, scope)
|
|
63
|
+
return None
|
|
64
|
+
|
|
22
65
|
def shadowed(self, name: str, at: ast.AST) -> bool:
|
|
23
66
|
return type_parameter_shadow(name, at, self.context)
|
|
24
67
|
|
|
@@ -158,10 +158,13 @@ def _bound_names(statement: ast.stmt) -> set[str]:
|
|
|
158
158
|
|
|
159
159
|
|
|
160
160
|
def _target_names(node: ast.expr) -> set[str]:
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
161
|
+
match node:
|
|
162
|
+
case ast.Name():
|
|
163
|
+
return {node.id}
|
|
164
|
+
case ast.List() | ast.Tuple():
|
|
165
|
+
return {name for item in node.elts for name in _target_names(item)}
|
|
166
|
+
case _:
|
|
167
|
+
pass
|
|
165
168
|
return set()
|
|
166
169
|
|
|
167
170
|
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
from collections import defaultdict
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from types import MappingProxyType
|
|
8
|
+
from typing import TYPE_CHECKING, final
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from sarj_python_lint._file_context import PythonFileContext
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
_SCOPES = (
|
|
16
|
+
ast.Module,
|
|
17
|
+
ast.FunctionDef,
|
|
18
|
+
ast.AsyncFunctionDef,
|
|
19
|
+
ast.ClassDef,
|
|
20
|
+
ast.Lambda,
|
|
21
|
+
ast.ListComp,
|
|
22
|
+
ast.SetComp,
|
|
23
|
+
ast.DictComp,
|
|
24
|
+
ast.GeneratorExp,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@final
|
|
29
|
+
@dataclass(frozen=True, slots=True)
|
|
30
|
+
class BindingInventory:
|
|
31
|
+
parents: Mapping[ast.AST, ast.AST]
|
|
32
|
+
bindings: Mapping[ast.AST | None, Mapping[str, tuple[ast.AST, ...]]]
|
|
33
|
+
reads: Mapping[str, tuple[ast.Name, ...]]
|
|
34
|
+
wildcard: bool
|
|
35
|
+
mutated: frozenset[str]
|
|
36
|
+
external_bindings: frozenset[str]
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def from_context(cls, context: PythonFileContext) -> BindingInventory:
|
|
40
|
+
parents = context.parents
|
|
41
|
+
bindings: dict[ast.AST | None, dict[str, list[ast.AST]]] = defaultdict(lambda: defaultdict(list))
|
|
42
|
+
reads: dict[str, list[ast.Name]] = defaultdict(list)
|
|
43
|
+
mutated: set[str] = set()
|
|
44
|
+
external_bindings: set[str] = set()
|
|
45
|
+
wildcard = False
|
|
46
|
+
for node in context.nodes(ast.AST):
|
|
47
|
+
if isinstance(node, ast.Name) and isinstance(node.ctx, ast.Load):
|
|
48
|
+
reads[node.id].append(node)
|
|
49
|
+
for name in _bound_names(node):
|
|
50
|
+
bindings[_binding_scope(parents, node)][name].append(node)
|
|
51
|
+
wildcard |= name == "*"
|
|
52
|
+
if isinstance(node, ast.Global | ast.Nonlocal):
|
|
53
|
+
external_bindings.update(node.names)
|
|
54
|
+
if (name := _mutated_namespace(node)) is not None:
|
|
55
|
+
mutated.add(name)
|
|
56
|
+
return cls(
|
|
57
|
+
parents=parents,
|
|
58
|
+
bindings=MappingProxyType(
|
|
59
|
+
{
|
|
60
|
+
scope: MappingProxyType({name: tuple(nodes) for name, nodes in names.items()})
|
|
61
|
+
for scope, names in bindings.items()
|
|
62
|
+
}
|
|
63
|
+
),
|
|
64
|
+
reads=MappingProxyType({name: tuple(nodes) for name, nodes in reads.items()}),
|
|
65
|
+
wildcard=wildcard,
|
|
66
|
+
mutated=frozenset(mutated),
|
|
67
|
+
external_bindings=frozenset(external_bindings),
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
def scope(self, node: ast.AST) -> ast.AST | None:
|
|
71
|
+
return _scope(self.parents, node)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _mutated_namespace(node: ast.AST) -> str | None:
|
|
75
|
+
if not isinstance(node, ast.Attribute) or not isinstance(node.ctx, ast.Store | ast.Del):
|
|
76
|
+
return None
|
|
77
|
+
root = node.value
|
|
78
|
+
while isinstance(root, ast.Attribute):
|
|
79
|
+
root = root.value
|
|
80
|
+
return root.id if isinstance(root, ast.Name) else None
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _scope(parents: Mapping[ast.AST, ast.AST], node: ast.AST) -> ast.AST | None:
|
|
84
|
+
parent = parents.get(node)
|
|
85
|
+
while parent is not None:
|
|
86
|
+
if isinstance(parent, ast.arguments) and (node in parent.defaults or node in parent.kw_defaults):
|
|
87
|
+
parent = parents.get(parent)
|
|
88
|
+
elif isinstance(parent, _SCOPES) and not (
|
|
89
|
+
(
|
|
90
|
+
isinstance(parent, ast.FunctionDef | ast.AsyncFunctionDef | ast.ClassDef)
|
|
91
|
+
and node in parent.decorator_list
|
|
92
|
+
)
|
|
93
|
+
or (isinstance(parent, ast.ClassDef) and (node in parent.bases or node in parent.keywords))
|
|
94
|
+
):
|
|
95
|
+
return parent
|
|
96
|
+
if parent is None:
|
|
97
|
+
return None
|
|
98
|
+
node = parent
|
|
99
|
+
parent = parents.get(parent)
|
|
100
|
+
return None
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _binding_scope(parents: Mapping[ast.AST, ast.AST], node: ast.AST) -> ast.AST | None:
|
|
104
|
+
scope = _scope(parents, node)
|
|
105
|
+
parent = parents.get(node)
|
|
106
|
+
if isinstance(parent, ast.NamedExpr) and parent.target is node:
|
|
107
|
+
while isinstance(scope, ast.ListComp | ast.SetComp | ast.DictComp | ast.GeneratorExp):
|
|
108
|
+
scope = _scope(parents, scope)
|
|
109
|
+
return scope
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _bound_names(node: ast.AST) -> tuple[str, ...]:
|
|
113
|
+
match node:
|
|
114
|
+
case ast.Name(id=name, ctx=ast.Store() | ast.Del()) | ast.arg(arg=name):
|
|
115
|
+
return (name,)
|
|
116
|
+
case ast.alias():
|
|
117
|
+
return (node.asname or node.name.partition(".")[0],)
|
|
118
|
+
case (
|
|
119
|
+
ast.FunctionDef(name=name)
|
|
120
|
+
| ast.AsyncFunctionDef(name=name)
|
|
121
|
+
| ast.ClassDef(name=name)
|
|
122
|
+
| ast.ExceptHandler(name=str() as name)
|
|
123
|
+
| ast.MatchAs(name=str() as name)
|
|
124
|
+
| ast.MatchStar(name=str() as name)
|
|
125
|
+
| ast.MatchMapping(rest=str() as name)
|
|
126
|
+
):
|
|
127
|
+
return (name,)
|
|
128
|
+
case ast.Global(names=names) | ast.Nonlocal(names=names):
|
|
129
|
+
return tuple(names)
|
|
130
|
+
case _:
|
|
131
|
+
return ()
|
{sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_closed_helpers.py
RENAMED
|
@@ -115,7 +115,7 @@ def call_matches(function: ast.FunctionDef, call: ast.Call) -> bool:
|
|
|
115
115
|
def stable_class(context: PythonFileContext, declaration: ast.ClassDef, provenance: ResourceProvenance) -> bool:
|
|
116
116
|
if declaration.decorator_list or declaration.keywords or context.parents.get(declaration) is not context.tree:
|
|
117
117
|
return False
|
|
118
|
-
return provenance.bindings.get(context.tree, {}).get(declaration.name) ==
|
|
118
|
+
return provenance.bindings.get(context.tree, {}).get(declaration.name) == (declaration,)
|
|
119
119
|
|
|
120
120
|
|
|
121
121
|
def plain_class_members(
|
{sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_copy_on_write.py
RENAMED
|
@@ -659,28 +659,37 @@ class CopyOnWriteAnalysis:
|
|
|
659
659
|
return _Value(_Shape("dict", element=element), shared_children=shared, fields=tuple(fields.items()))
|
|
660
660
|
|
|
661
661
|
def _write(self, target: ast.expr, bindings: Mapping[str, _Value]) -> None:
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
662
|
+
match target:
|
|
663
|
+
case ast.Tuple() | ast.List():
|
|
664
|
+
for item in target.elts:
|
|
665
|
+
self._write(item, bindings)
|
|
666
|
+
case ast.Attribute() | ast.Subscript():
|
|
667
|
+
owner = self._value(target.value, bindings)
|
|
668
|
+
if (
|
|
669
|
+
owner is not None
|
|
670
|
+
and owner.borrowed
|
|
671
|
+
and (
|
|
672
|
+
isinstance(target, ast.Subscript)
|
|
673
|
+
or (
|
|
674
|
+
owner.shape.model is not None
|
|
675
|
+
and self.models.field(owner.shape.model, target.attr) is not None
|
|
676
|
+
)
|
|
677
|
+
)
|
|
678
|
+
):
|
|
679
|
+
self.mutations.append(Mutation(target, self._before))
|
|
680
|
+
case _:
|
|
681
|
+
pass
|
|
676
682
|
|
|
677
683
|
def _expression(self, node: ast.AST, bindings: dict[str, _Value]) -> None:
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
+
match node:
|
|
685
|
+
case ast.Lambda() | ast.FunctionDef() | ast.AsyncFunctionDef() | ast.ClassDef():
|
|
686
|
+
return
|
|
687
|
+
case ast.NamedExpr():
|
|
688
|
+
self._expression(node.value, bindings)
|
|
689
|
+
self._bind(node.target, self._value(node.value, bindings), bindings)
|
|
690
|
+
return
|
|
691
|
+
case _:
|
|
692
|
+
pass
|
|
684
693
|
if isinstance(node, ast.Call) and self._mutator_call(node, bindings):
|
|
685
694
|
self.mutations.append(Mutation(node, self._before))
|
|
686
695
|
if isinstance(node, (ast.ListComp, ast.SetComp, ast.GeneratorExp, ast.DictComp)):
|
|
@@ -11,6 +11,8 @@ from sarj_python_lint.rules._resource_provenance import ResourceProvenance
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
14
|
+
from collections.abc import Mapping, Sequence
|
|
15
|
+
|
|
14
16
|
from sarj_python_lint._file_context import PythonFileContext
|
|
15
17
|
|
|
16
18
|
|
|
@@ -757,7 +759,7 @@ def _metadata_tuple_index(node: ast.expr) -> int | None:
|
|
|
757
759
|
return None
|
|
758
760
|
|
|
759
761
|
|
|
760
|
-
def _metadata_alias_graph(tree: ast.Module, bindings:
|
|
762
|
+
def _metadata_alias_graph(tree: ast.Module, bindings: Mapping[str, Sequence[ast.AST]]) -> dict[str, set[str]]:
|
|
761
763
|
graph: dict[str, set[str]] = {}
|
|
762
764
|
for node in tree.body:
|
|
763
765
|
binding = _value_binding(node)
|
{sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_docstrings.py
RENAMED
|
@@ -305,10 +305,13 @@ def base_names(node: ast.ClassDef) -> set[str]:
|
|
|
305
305
|
names: set[str] = set()
|
|
306
306
|
for base in node.bases:
|
|
307
307
|
target = base.value if isinstance(base, ast.Subscript) else base
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
308
|
+
match target:
|
|
309
|
+
case ast.Attribute():
|
|
310
|
+
names.add(target.attr)
|
|
311
|
+
case ast.Name():
|
|
312
|
+
names.add(target.id)
|
|
313
|
+
case _:
|
|
314
|
+
pass
|
|
312
315
|
return names
|
|
313
316
|
|
|
314
317
|
|
|
@@ -241,10 +241,13 @@ class FastapiIndex:
|
|
|
241
241
|
for node in walk_ast(tree):
|
|
242
242
|
if self._node_scopes[id(node)] != 0:
|
|
243
243
|
continue
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
244
|
+
match node:
|
|
245
|
+
case ast.Import():
|
|
246
|
+
self._read_import(node)
|
|
247
|
+
case ast.ImportFrom():
|
|
248
|
+
self._read_import_from(node)
|
|
249
|
+
case _:
|
|
250
|
+
pass
|
|
248
251
|
|
|
249
252
|
def _read_import(self, node: ast.Import) -> None:
|
|
250
253
|
for alias in node.names:
|
|
@@ -141,10 +141,13 @@ def _module_non_import_bindings(tree: ast.Module) -> set[str]:
|
|
|
141
141
|
|
|
142
142
|
|
|
143
143
|
def _target_names(node: ast.expr) -> set[str]:
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
144
|
+
match node:
|
|
145
|
+
case ast.Name():
|
|
146
|
+
return {node.id}
|
|
147
|
+
case ast.Tuple() | ast.List():
|
|
148
|
+
return {name for element in node.elts for name in _target_names(element)}
|
|
149
|
+
case _:
|
|
150
|
+
pass
|
|
148
151
|
return set()
|
|
149
152
|
|
|
150
153
|
|
|
@@ -59,14 +59,17 @@ class RawMappingCallbacks:
|
|
|
59
59
|
def callback(self, node: ast.expr, *, seen: frozenset[ast.AST] = frozenset()) -> _Function | None:
|
|
60
60
|
if len(seen) >= _MAX_DEPTH:
|
|
61
61
|
return None
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
62
|
+
match node:
|
|
63
|
+
case ast.Call():
|
|
64
|
+
return (
|
|
65
|
+
self._partial(node, seen)
|
|
66
|
+
if self.qualified(node.func, node) == "functools.partial"
|
|
67
|
+
else self._method(node, "__call__", seen)
|
|
68
|
+
)
|
|
69
|
+
case ast.Attribute():
|
|
70
|
+
return self._method(node.value, node.attr, seen)
|
|
71
|
+
case _:
|
|
72
|
+
pass
|
|
70
73
|
if not isinstance(node, ast.Name) or not self._stable(node.id) or self.shadowed(node.id, node):
|
|
71
74
|
return None
|
|
72
75
|
binding = self.provenance.binding(node.id, node)
|
|
@@ -144,10 +147,13 @@ class RawMappingCallbacks:
|
|
|
144
147
|
def _function(self, node: ast.AST) -> _Function | None:
|
|
145
148
|
current = self.context.parents.get(node)
|
|
146
149
|
while current is not None:
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
150
|
+
match current:
|
|
151
|
+
case ast.FunctionDef() | ast.AsyncFunctionDef():
|
|
152
|
+
return current
|
|
153
|
+
case ast.ClassDef() | ast.Lambda():
|
|
154
|
+
return None
|
|
155
|
+
case _:
|
|
156
|
+
pass
|
|
151
157
|
current = self.context.parents.get(current)
|
|
152
158
|
return None
|
|
153
159
|
|
|
@@ -406,11 +406,14 @@ class _NamespaceFlow:
|
|
|
406
406
|
def plain_dict(self, value: ast.expr, *, depth: int = 0) -> bool:
|
|
407
407
|
if depth >= _MAX_DEPTH:
|
|
408
408
|
return False
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
409
|
+
match value:
|
|
410
|
+
case ast.Name():
|
|
411
|
+
assigned = self.assigned(value)
|
|
412
|
+
return assigned is not None and self.plain_dict(assigned, depth=depth + 1)
|
|
413
|
+
case ast.IfExp():
|
|
414
|
+
return self.plain_dict(value.body, depth=depth + 1) and self.plain_dict(value.orelse, depth=depth + 1)
|
|
415
|
+
case _:
|
|
416
|
+
pass
|
|
414
417
|
return isinstance(value, ast.Dict) or (isinstance(value, ast.Call) and self.native.dict_call(value))
|
|
415
418
|
|
|
416
419
|
def _collect(self, value: ast.expr, *, execution: ast.Call, depth: int = 0) -> None:
|
|
@@ -436,10 +439,13 @@ class _NamespaceFlow:
|
|
|
436
439
|
def _input(self, value: ast.expr, *, depth: int = 0) -> set[ast.arg]:
|
|
437
440
|
if depth >= _MAX_DEPTH:
|
|
438
441
|
return set()
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
442
|
+
match value:
|
|
443
|
+
case ast.Name():
|
|
444
|
+
return self._name_input(value, depth)
|
|
445
|
+
case ast.Dict():
|
|
446
|
+
return self._dictionary_inputs(value, depth)
|
|
447
|
+
case _:
|
|
448
|
+
pass
|
|
443
449
|
if isinstance(value, ast.Call) and self.native.dict_call(value):
|
|
444
450
|
return self._constructor_inputs(value, depth)
|
|
445
451
|
found: set[ast.arg] = set()
|
|
@@ -652,13 +658,16 @@ class _NamespaceEscapes:
|
|
|
652
658
|
return None
|
|
653
659
|
binding = self.flow.binding(value)
|
|
654
660
|
found: set[ast.AST] = {binding} if binding is not None else set()
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
661
|
+
match value:
|
|
662
|
+
case ast.Name():
|
|
663
|
+
assigned = self.flow.assigned(value)
|
|
664
|
+
if isinstance(assigned, ast.Name | ast.Subscript):
|
|
665
|
+
previous = self._carrier_roots(assigned, depth=depth + 1)
|
|
666
|
+
return None if previous is None else found | previous
|
|
667
|
+
case ast.Subscript():
|
|
668
|
+
return self._carrier_roots(value.value, depth=depth + 1)
|
|
669
|
+
case _:
|
|
670
|
+
pass
|
|
662
671
|
return found
|
|
663
672
|
|
|
664
673
|
|
{sarj_python_lint-1.83.0 → sarj_python_lint-1.84.0}/src/sarj_python_lint/rules/_opaque_contracts.py
RENAMED
|
@@ -427,10 +427,13 @@ class OpaqueContractFacts:
|
|
|
427
427
|
|
|
428
428
|
def _enclosing_assertion(self, node: ast.AST) -> ast.Assert | None:
|
|
429
429
|
while (parent := self.context.parents.get(node)) is not None:
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
430
|
+
match parent:
|
|
431
|
+
case ast.Assert():
|
|
432
|
+
return parent
|
|
433
|
+
case ast.FunctionDef() | ast.AsyncFunctionDef() | ast.Lambda():
|
|
434
|
+
return None
|
|
435
|
+
case _:
|
|
436
|
+
pass
|
|
434
437
|
node = parent
|
|
435
438
|
return None
|
|
436
439
|
|
|
@@ -534,11 +537,14 @@ class OpaqueContractFacts:
|
|
|
534
537
|
return None
|
|
535
538
|
if isinstance(node, ast.Name):
|
|
536
539
|
binding = self.facts.provenance.runtime_binding(node.id, node)
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
540
|
+
match binding:
|
|
541
|
+
case ast.arg():
|
|
542
|
+
return binding
|
|
543
|
+
case ast.Name():
|
|
544
|
+
value = self.assigned(binding, node)
|
|
545
|
+
return self.parameter(value, depth=depth + 1) if value is not None else None
|
|
546
|
+
case _:
|
|
547
|
+
pass
|
|
542
548
|
receiver = _projection_receiver(node)
|
|
543
549
|
parameter = self.parameter(receiver, depth=depth + 1) if receiver is not None else None
|
|
544
550
|
return parameter if self._raw_annotation(parameter) else None
|
|
@@ -993,12 +999,13 @@ def _projection_receiver(node: ast.expr) -> ast.expr | None:
|
|
|
993
999
|
|
|
994
1000
|
|
|
995
1001
|
def _control_condition(node: ast.AST, parent: ast.AST) -> tuple[ast.expr, bool] | None:
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
+
match parent:
|
|
1003
|
+
case ast.IfExp():
|
|
1004
|
+
accepted, rejected = node is parent.body, node is parent.orelse
|
|
1005
|
+
case ast.If():
|
|
1006
|
+
accepted, rejected = node in parent.body, node in parent.orelse
|
|
1007
|
+
case _:
|
|
1008
|
+
return None
|
|
1002
1009
|
return (parent.test, accepted) if accepted or rejected else None
|
|
1003
1010
|
|
|
1004
1011
|
|