sarj-python-lint 1.66.0__tar.gz → 1.66.1__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.66.0 → sarj_python_lint-1.66.1}/PKG-INFO +1 -1
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/pyproject.toml +1 -1
- sarj_python_lint-1.66.1/src/sarj_python_lint/rules/_ast_names.py +63 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_closed_helpers.py +10 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_comments.py +30 -4
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_docstrings.py +19 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +1 -8
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +2 -23
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +2 -21
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_any_mapping_types.py +1 -6
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_contradictory_type_guard.py +2 -8
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_generic_single_export_module.py +1 -8
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -9
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +1 -6
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_partial_type_is.py +2 -8
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -8
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +1 -7
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_select_star.py +1 -8
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_shallow_record_type_guard.py +2 -8
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_typed_doc_sections.py +1 -8
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +1 -6
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/over_mocked_test.py +1 -12
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_class_row.py +1 -6
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +2 -12
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +6 -24
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +20 -11
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +2 -4
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +2 -4
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_module_level_constant.py +1 -6
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +2 -4
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +1 -8
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +1 -6
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +1 -8
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +2 -11
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/production_derived_test_cases.py +1 -15
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +1 -8
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/repeated_static_call_cases.py +1 -9
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +2 -20
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/require_precise_factory_signature.py +2 -17
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +1 -13
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +1 -6
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/restated_test_docstring.py +11 -25
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +1 -10
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/typed_error_reasons.py +1 -8
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +1 -15
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/unused_mock_setup.py +1 -12
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/.gitignore +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/LICENSE +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/README.md +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/__init__.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/__main__.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/_analysis_session.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/_file_context.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/_filesystem.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/_python_target.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/_ratchet_cli.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/_secret_names.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/_source.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/_version.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/benchmark.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/cast_access.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/interpreter_argv.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/json_boundary.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/py.typed +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/ratchet.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rule_base.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/__init__.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_ast_index.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_ast_position.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_copy_on_write.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_data_union_discriminator.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_exports.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_fastapi.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_first_party.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_imports.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_inert_model_annotation.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_inherited_contract.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_local_source.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_logging.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_mapping_shape_callbacks.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_namespace_access.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_native_namespace_capability.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_paths.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_project_index.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_pydantic_field_contract.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_pytest.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_registry.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_resolved_operation_signature.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_route_shapes.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_runtime_bindings.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_set_fields.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_sql.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_static_json_alias.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_store_writes.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_test_composition.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_test_provenance.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_type_guard_symbols.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/delete_route_returns_no_content.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/duplicate_adjacent_exception_handler.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/duplicate_closed_pure_helper.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_async_function_cache.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_before_validator_input_mutation.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_blanket_suppression.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_broad_keyword_capture.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_conflicting_pydantic_alias_validation.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_create_verb_in_post_path.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_defaulted_environment_setting.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_discarded_validation_result.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_dual_shape_model_field_reader.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_duplicate_field_validator_body.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_exception_text_in_500_detail.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_fixed_sleep_in_loop.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_folded_bad_request_not_found.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_hasattr.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_impossible_pydantic_field_bounds.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_input_model_mutation.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_interpreter_source_arguments.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_invalid_pydantic_bypass.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_invalid_pydantic_validator_return.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_loguru_exc_info.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_loguru_printf_format.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_mocked_pydantic_value_object.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_mutating_container_transform.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_slash_collection_root_under_prefix.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_test_method_grafting.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_unknown_pydantic_validator_field.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_unused_copy_result.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_work_verb_get_route.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_bulk_upsert.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_declarative_batch_validation.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_discriminated_model_union.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_native_string_check.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_psycopg_executemany.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_required_constructor_parameters.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/redundant_test_constructor_forwarder.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/repeated_unimplemented_test_contract.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/require_exp_on_jwt_decode.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/require_injectable_retry_sleep.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/require_pydantic_for_mapping_shape.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/stepdown.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/store_field_update_reuses_upsert.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/test_without_explicit_oracle.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/unused_test_factory_option.py +0 -0
- {sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/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.66.
|
|
3
|
+
Version: 1.66.1
|
|
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/
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def root_name(node: ast.expr) -> str | None:
|
|
7
|
+
while isinstance(node, ast.Attribute):
|
|
8
|
+
node = node.value
|
|
9
|
+
return node.id if isinstance(node, ast.Name) else None
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def expression_root(node: ast.expr) -> str | None:
|
|
13
|
+
while isinstance(node, (ast.Attribute, ast.Subscript)):
|
|
14
|
+
node = node.value
|
|
15
|
+
return node.id if isinstance(node, ast.Name) else None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def terminal_name(node: ast.expr) -> str | None:
|
|
19
|
+
match node:
|
|
20
|
+
case ast.Name(id=name) | ast.Attribute(attr=name):
|
|
21
|
+
return name
|
|
22
|
+
case _:
|
|
23
|
+
return None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def unqualified_name(node: ast.expr) -> str:
|
|
27
|
+
match node:
|
|
28
|
+
case ast.Name(id=name) | ast.Attribute(attr=name):
|
|
29
|
+
return name
|
|
30
|
+
case _:
|
|
31
|
+
return ""
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def dotted_parts(node: ast.expr) -> tuple[str, ...] | None:
|
|
35
|
+
parts: list[str] = []
|
|
36
|
+
current = node
|
|
37
|
+
while isinstance(current, ast.Attribute):
|
|
38
|
+
parts.append(current.attr)
|
|
39
|
+
current = current.value
|
|
40
|
+
if not isinstance(current, ast.Name):
|
|
41
|
+
return None
|
|
42
|
+
parts.append(current.id)
|
|
43
|
+
return tuple(reversed(parts))
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def dotted_name(node: ast.expr) -> str | None:
|
|
47
|
+
parts = dotted_parts(node)
|
|
48
|
+
return ".".join(parts) if parts is not None else None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def assignment_names(node: ast.AST) -> set[str]:
|
|
52
|
+
match node:
|
|
53
|
+
case ast.Name(id=name):
|
|
54
|
+
return {name}
|
|
55
|
+
case ast.Tuple() | ast.List():
|
|
56
|
+
names: set[str] = set()
|
|
57
|
+
for element in node.elts:
|
|
58
|
+
names.update(assignment_names(element))
|
|
59
|
+
return names
|
|
60
|
+
case ast.Starred(value=value):
|
|
61
|
+
return assignment_names(value)
|
|
62
|
+
case _:
|
|
63
|
+
return set()
|
{sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_closed_helpers.py
RENAMED
|
@@ -183,3 +183,13 @@ def _plain_decorator(
|
|
|
183
183
|
and not (keyword.arg == "mode" and isinstance(keyword.value, ast.Constant) and keyword.value.value == "wrap")
|
|
184
184
|
for keyword in decorator.keywords
|
|
185
185
|
)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def closed_owner(function: ast.FunctionDef | ast.AsyncFunctionDef, context: PythonFileContext) -> bool:
|
|
189
|
+
if not isinstance(function, ast.FunctionDef) or not function.name.startswith("_"):
|
|
190
|
+
return False
|
|
191
|
+
references = closed_references(context, function, context.resource_provenance)
|
|
192
|
+
return bool(references) and all(
|
|
193
|
+
(call := direct_call(reference, context)) is not None and call_matches(function, call)
|
|
194
|
+
for reference in references
|
|
195
|
+
)
|
|
@@ -326,7 +326,13 @@ class _Scan(NamedTuple):
|
|
|
326
326
|
ordered: _Ordered
|
|
327
327
|
|
|
328
328
|
|
|
329
|
-
|
|
329
|
+
class _ScanMemo(NamedTuple):
|
|
330
|
+
source: str
|
|
331
|
+
scan: _Scan | None
|
|
332
|
+
comment_lines: frozenset[int] | None
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
_last_scan: _ScanMemo | None = None
|
|
330
336
|
|
|
331
337
|
|
|
332
338
|
def all_comments(source: str) -> _CommentScan[_Ordered]:
|
|
@@ -334,15 +340,35 @@ def all_comments(source: str) -> _CommentScan[_Ordered]:
|
|
|
334
340
|
return _CommentScan(scan.ordered, scan.first_code_line)
|
|
335
341
|
|
|
336
342
|
|
|
343
|
+
def comment_line_numbers(source: str) -> frozenset[int]:
|
|
344
|
+
global _last_scan # ruff: ignore[global-statement] -- retain the existing single-source memo for both comment projections.
|
|
345
|
+
cached = _last_scan
|
|
346
|
+
scan = cached.scan if cached is not None and cached.source is source else None
|
|
347
|
+
if cached is not None and cached.source is source and cached.comment_lines is not None:
|
|
348
|
+
return cached.comment_lines
|
|
349
|
+
lines: frozenset[int]
|
|
350
|
+
if scan is not None:
|
|
351
|
+
lines = frozenset(comment.line for comment in scan.ordered)
|
|
352
|
+
else:
|
|
353
|
+
try:
|
|
354
|
+
tokens = tokenize.generate_tokens(io.StringIO(source).readline)
|
|
355
|
+
lines = frozenset(token.start[0] for token in tokens if token.type == tokenize.COMMENT)
|
|
356
|
+
except IndentationError, tokenize.TokenError:
|
|
357
|
+
lines = frozenset()
|
|
358
|
+
_last_scan = _ScanMemo(source, scan, lines)
|
|
359
|
+
return lines
|
|
360
|
+
|
|
361
|
+
|
|
337
362
|
def _scan_memo(source: str) -> _Scan:
|
|
338
363
|
global _last_scan # ruff: ignore[global-statement] — single-slot memo; the CLI runs rules per file sequentially
|
|
339
|
-
if _last_scan is not None and _last_scan
|
|
340
|
-
|
|
364
|
+
cached = _last_scan if _last_scan is not None and _last_scan.source is source else None
|
|
365
|
+
if cached is not None and cached.scan is not None:
|
|
366
|
+
return cached.scan
|
|
341
367
|
try:
|
|
342
368
|
result = _scan(source)
|
|
343
369
|
except UnicodeError:
|
|
344
370
|
result = _Scan([], [], set(), 1 << 30, [])
|
|
345
|
-
_last_scan = (source, result)
|
|
371
|
+
_last_scan = _ScanMemo(source, result, cached.comment_lines if cached is not None else None)
|
|
346
372
|
return result
|
|
347
373
|
|
|
348
374
|
|
{sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/_docstrings.py
RENAMED
|
@@ -13,9 +13,16 @@ if TYPE_CHECKING:
|
|
|
13
13
|
from collections.abc import Iterable
|
|
14
14
|
|
|
15
15
|
from sarj_python_lint.rules._ast_index import NodeIndex
|
|
16
|
+
from sarj_python_lint.rules._imports import ImportIndex
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
_GETATTR_MIN_ARGS = 2
|
|
20
|
+
_RUNTIME_DOC_DECORATORS = (
|
|
21
|
+
(frozenset({"agents"}), "function_tool"),
|
|
22
|
+
(frozenset({"click"}), "command"),
|
|
23
|
+
(frozenset({"typer"}), "command"),
|
|
24
|
+
)
|
|
25
|
+
_OVERLOAD_MODULES = frozenset({"typing", "typing_extensions"})
|
|
19
26
|
|
|
20
27
|
# Docstring filler that says nothing about *which* thing is being described.
|
|
21
28
|
_BASE_STOPWORDS = frozenset(
|
|
@@ -259,6 +266,18 @@ def decorator_markers(node: ast.FunctionDef | ast.AsyncFunctionDef | ast.ClassDe
|
|
|
259
266
|
return markers
|
|
260
267
|
|
|
261
268
|
|
|
269
|
+
def is_runtime_consumed_or_overload(node: ast.FunctionDef | ast.AsyncFunctionDef, imports: ImportIndex) -> bool:
|
|
270
|
+
if decorator_markers(node) & PROMPT_DECORATOR_MARKERS:
|
|
271
|
+
return True
|
|
272
|
+
for decorator in node.decorator_list:
|
|
273
|
+
target = decorator.func if isinstance(decorator, ast.Call) else decorator
|
|
274
|
+
if imports.resolves(target, sources=_OVERLOAD_MODULES, symbol="overload"):
|
|
275
|
+
return True
|
|
276
|
+
if any(imports.resolves(target, sources=sources, symbol=symbol) for sources, symbol in _RUNTIME_DOC_DECORATORS):
|
|
277
|
+
return True
|
|
278
|
+
return False
|
|
279
|
+
|
|
280
|
+
|
|
262
281
|
def docstring_expression(
|
|
263
282
|
node: ast.Module | ast.ClassDef | ast.FunctionDef | ast.AsyncFunctionDef,
|
|
264
283
|
) -> ast.Expr | None:
|
|
@@ -17,6 +17,7 @@ from sarj_python_lint.rule_base import (
|
|
|
17
17
|
Severity,
|
|
18
18
|
)
|
|
19
19
|
from sarj_python_lint.rules._ast_index import nodes, walk
|
|
20
|
+
from sarj_python_lint.rules._ast_names import unqualified_name as _call_name
|
|
20
21
|
from sarj_python_lint.rules._paths import is_test_path
|
|
21
22
|
from sarj_python_lint.rules._sql import is_store_module, sql_string_value, strip_sql_noise
|
|
22
23
|
from sarj_python_lint.rules.no_analytical_aggregation_in_postgres_store import analytical_signal
|
|
@@ -148,14 +149,6 @@ def _query_argument(call: ast.Call) -> ast.expr | None:
|
|
|
148
149
|
return next((keyword.value for keyword in call.keywords if keyword.arg in _QUERY_KEYWORDS), None)
|
|
149
150
|
|
|
150
151
|
|
|
151
|
-
def _call_name(function: ast.expr) -> str:
|
|
152
|
-
match function:
|
|
153
|
-
case ast.Name(id=name) | ast.Attribute(attr=name):
|
|
154
|
-
return name
|
|
155
|
-
case _:
|
|
156
|
-
return ""
|
|
157
|
-
|
|
158
|
-
|
|
159
152
|
def _postgres_sql_constructors(
|
|
160
153
|
tree: ast.Module, parents: Mapping[ast.AST, ast.AST], *, node_index: NodeIndex | None = None
|
|
161
154
|
) -> frozenset[_ConstructorImport]:
|
|
@@ -20,13 +20,12 @@ from sarj_python_lint.rule_base import (
|
|
|
20
20
|
from sarj_python_lint.rules._ast_index import children
|
|
21
21
|
from sarj_python_lint.rules._comments import is_protected, stem
|
|
22
22
|
from sarj_python_lint.rules._docstrings import (
|
|
23
|
-
PROMPT_DECORATOR_MARKERS,
|
|
24
23
|
VALUE_MARKER_RE,
|
|
25
24
|
annotation_tokens,
|
|
26
25
|
arg_entries,
|
|
27
26
|
arg_section,
|
|
28
|
-
decorator_markers,
|
|
29
27
|
identifier_stems,
|
|
28
|
+
is_runtime_consumed_or_overload,
|
|
30
29
|
restates,
|
|
31
30
|
)
|
|
32
31
|
|
|
@@ -40,14 +39,6 @@ if TYPE_CHECKING:
|
|
|
40
39
|
|
|
41
40
|
_ARGUMENT_CONSTRAINT_RE = re.compile(r"\b(available|current|existing|optional|required|supported)\b", re.IGNORECASE)
|
|
42
41
|
|
|
43
|
-
_RUNTIME_DOC_DECORATORS = (
|
|
44
|
-
(frozenset({"agents"}), "function_tool"),
|
|
45
|
-
(frozenset({"click"}), "command"),
|
|
46
|
-
(frozenset({"typer"}), "command"),
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
_OVERLOAD_MODULES = frozenset({"typing", "typing_extensions"})
|
|
50
|
-
|
|
51
42
|
|
|
52
43
|
@dataclass(frozen=True, slots=True)
|
|
53
44
|
class _ParameterFacts:
|
|
@@ -151,7 +142,7 @@ class DocstringArgsRestateSignature(Rule):
|
|
|
151
142
|
block = arg_section(docstring)
|
|
152
143
|
if block is None or VALUE_MARKER_RE.search(block) or is_protected(block):
|
|
153
144
|
return
|
|
154
|
-
if
|
|
145
|
+
if is_runtime_consumed_or_overload(node, imports):
|
|
155
146
|
return
|
|
156
147
|
entries = arg_entries(block)
|
|
157
148
|
if not entries:
|
|
@@ -202,15 +193,3 @@ def _parameter_stems(
|
|
|
202
193
|
known = callable_stems | identifier_stems(argument.arg) | annotation_stems
|
|
203
194
|
parameters[argument.arg] = _ParameterFacts(frozenset(known), frozenset(annotation_stems))
|
|
204
195
|
return parameters
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
def _is_runtime_consumed_or_overload(node: ast.FunctionDef | ast.AsyncFunctionDef, imports: ImportIndex) -> bool:
|
|
208
|
-
if decorator_markers(node) & PROMPT_DECORATOR_MARKERS:
|
|
209
|
-
return True
|
|
210
|
-
for decorator in node.decorator_list:
|
|
211
|
-
target = decorator.func if isinstance(decorator, ast.Call) else decorator
|
|
212
|
-
if imports.resolves(target, sources=_OVERLOAD_MODULES, symbol="overload"):
|
|
213
|
-
return True
|
|
214
|
-
if any(imports.resolves(target, sources=sources, symbol=symbol) for sources, symbol in _RUNTIME_DOC_DECORATORS):
|
|
215
|
-
return True
|
|
216
|
-
return False
|
|
@@ -20,11 +20,10 @@ from sarj_python_lint.rule_base import (
|
|
|
20
20
|
from sarj_python_lint.rules._ast_index import children
|
|
21
21
|
from sarj_python_lint.rules._comments import is_protected, stem
|
|
22
22
|
from sarj_python_lint.rules._docstrings import (
|
|
23
|
-
PROMPT_DECORATOR_MARKERS,
|
|
24
23
|
VALUE_MARKER_RE,
|
|
25
24
|
annotation_tokens,
|
|
26
|
-
decorator_markers,
|
|
27
25
|
identifier_stems,
|
|
26
|
+
is_runtime_consumed_or_overload,
|
|
28
27
|
restates,
|
|
29
28
|
sections,
|
|
30
29
|
)
|
|
@@ -51,12 +50,6 @@ _RESULT_SEMANTIC_RE = re.compile(
|
|
|
51
50
|
re.IGNORECASE,
|
|
52
51
|
)
|
|
53
52
|
|
|
54
|
-
_RUNTIME_DOC_DECORATORS = (
|
|
55
|
-
(frozenset({"agents"}), "function_tool"),
|
|
56
|
-
(frozenset({"click"}), "command"),
|
|
57
|
-
(frozenset({"typer"}), "command"),
|
|
58
|
-
)
|
|
59
|
-
_OVERLOAD_MODULES = frozenset({"typing", "typing_extensions"})
|
|
60
53
|
_GENERATOR_TYPES = frozenset({"AsyncGenerator", "AsyncIterable", "AsyncIterator", "Generator", "Iterable", "Iterator"})
|
|
61
54
|
_BROAD_RETURN_TYPES = frozenset({"Any", "object"})
|
|
62
55
|
|
|
@@ -228,7 +221,7 @@ class DocstringReturnsRestateSignature(Rule):
|
|
|
228
221
|
or _TYPED_RESULT_RE.search(block)
|
|
229
222
|
):
|
|
230
223
|
return
|
|
231
|
-
if
|
|
224
|
+
if is_runtime_consumed_or_overload(node, imports):
|
|
232
225
|
return
|
|
233
226
|
annotation = _result_annotation(node, section.name)
|
|
234
227
|
if annotation is None or _is_broad_annotation(annotation):
|
|
@@ -313,15 +306,3 @@ def _contains_yield(node: ast.FunctionDef | ast.AsyncFunctionDef) -> bool:
|
|
|
313
306
|
|
|
314
307
|
def _is_broad_annotation(annotation: ast.expr) -> bool:
|
|
315
308
|
return _annotation_name(annotation) in _BROAD_RETURN_TYPES
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
def _is_runtime_consumed_or_overload(node: ast.FunctionDef | ast.AsyncFunctionDef, imports: ImportIndex) -> bool:
|
|
319
|
-
if decorator_markers(node) & PROMPT_DECORATOR_MARKERS:
|
|
320
|
-
return True
|
|
321
|
-
for decorator in node.decorator_list:
|
|
322
|
-
target = decorator.func if isinstance(decorator, ast.Call) else decorator
|
|
323
|
-
if imports.resolves(target, sources=_OVERLOAD_MODULES, symbol="overload"):
|
|
324
|
-
return True
|
|
325
|
-
if any(imports.resolves(target, sources=sources, symbol=symbol) for sources, symbol in _RUNTIME_DOC_DECORATORS):
|
|
326
|
-
return True
|
|
327
|
-
return False
|
|
@@ -21,6 +21,7 @@ from sarj_python_lint.rule_base import (
|
|
|
21
21
|
)
|
|
22
22
|
from sarj_python_lint.rules._annotation_semantics import AnnotationSemantics, scope_bound_names
|
|
23
23
|
from sarj_python_lint.rules._ast_index import walk as walk_ast
|
|
24
|
+
from sarj_python_lint.rules._ast_names import expression_root as _expression_root
|
|
24
25
|
from sarj_python_lint.rules._namespace_access import dynamic_namespace_access
|
|
25
26
|
|
|
26
27
|
|
|
@@ -568,12 +569,6 @@ def _type_attribute_mutation(call: ast.Call, imports: ImportIndex, sensitive: se
|
|
|
568
569
|
return known and _expression_root(call.args[0]) in sensitive
|
|
569
570
|
|
|
570
571
|
|
|
571
|
-
def _expression_root(node: ast.expr) -> str | None:
|
|
572
|
-
while isinstance(node, (ast.Attribute, ast.Subscript)):
|
|
573
|
-
node = node.value
|
|
574
|
-
return node.id if isinstance(node, ast.Name) else None
|
|
575
|
-
|
|
576
|
-
|
|
577
572
|
def _unshadowed_type_expression(
|
|
578
573
|
node: ast.expr, parents: Mapping[ast.AST, ast.AST], scope_cache: dict[int, frozenset[str]]
|
|
579
574
|
) -> bool:
|
|
@@ -16,6 +16,7 @@ from sarj_python_lint.rule_base import (
|
|
|
16
16
|
Severity,
|
|
17
17
|
is_suppressed,
|
|
18
18
|
)
|
|
19
|
+
from sarj_python_lint.rules._closed_helpers import executable_body
|
|
19
20
|
from sarj_python_lint.rules._imports import TYPING_SOURCES
|
|
20
21
|
from sarj_python_lint.rules._type_guard_symbols import (
|
|
21
22
|
builtin_guard_symbol,
|
|
@@ -189,14 +190,7 @@ def _sole_parameter(function: ast.FunctionDef) -> ast.arg | None:
|
|
|
189
190
|
|
|
190
191
|
|
|
191
192
|
def _single_return(function: ast.FunctionDef) -> ast.Return | None:
|
|
192
|
-
body = function
|
|
193
|
-
if (
|
|
194
|
-
body
|
|
195
|
-
and isinstance(body[0], ast.Expr)
|
|
196
|
-
and isinstance(body[0].value, ast.Constant)
|
|
197
|
-
and isinstance(body[0].value.value, str)
|
|
198
|
-
):
|
|
199
|
-
body = body[1:]
|
|
193
|
+
body = executable_body(function)
|
|
200
194
|
return body[0] if len(body) == 1 and isinstance(body[0], ast.Return) else None
|
|
201
195
|
|
|
202
196
|
|
|
@@ -15,6 +15,7 @@ from sarj_python_lint.rule_base import (
|
|
|
15
15
|
RuleExample,
|
|
16
16
|
)
|
|
17
17
|
from sarj_python_lint.rules._ast_index import walk as walk_ast
|
|
18
|
+
from sarj_python_lint.rules._ast_names import unqualified_name as _annotation_name
|
|
18
19
|
from sarj_python_lint.rules._exports import mentions_dunder_all
|
|
19
20
|
|
|
20
21
|
|
|
@@ -164,14 +165,6 @@ def _dunder_all_matches_primary(tree: ast.Module, primary_name: str) -> bool:
|
|
|
164
165
|
return isinstance(entry, ast.Constant) and entry.value == primary_name
|
|
165
166
|
|
|
166
167
|
|
|
167
|
-
def _annotation_name(node: ast.expr) -> str:
|
|
168
|
-
match node:
|
|
169
|
-
case ast.Name(id=name) | ast.Attribute(attr=name):
|
|
170
|
-
return name
|
|
171
|
-
case _:
|
|
172
|
-
return ""
|
|
173
|
-
|
|
174
|
-
|
|
175
168
|
def _is_skipped_path(path: Path) -> bool:
|
|
176
169
|
return "tests" in path.parts
|
|
177
170
|
|
|
@@ -368,15 +368,6 @@ def _directly_bound_names(statement: ast.stmt) -> set[str]:
|
|
|
368
368
|
return set()
|
|
369
369
|
|
|
370
370
|
|
|
371
|
-
def _argument_names(arguments: ast.arguments) -> set[str]:
|
|
372
|
-
names = {argument.arg for argument in (*arguments.posonlyargs, *arguments.args, *arguments.kwonlyargs)}
|
|
373
|
-
if arguments.vararg is not None:
|
|
374
|
-
names.add(arguments.vararg.arg)
|
|
375
|
-
if arguments.kwarg is not None:
|
|
376
|
-
names.add(arguments.kwarg.arg)
|
|
377
|
-
return names
|
|
378
|
-
|
|
379
|
-
|
|
380
371
|
def _target_names(target: ast.expr) -> set[str]:
|
|
381
372
|
if isinstance(target, ast.Name):
|
|
382
373
|
return {target.id}
|
|
@@ -14,6 +14,7 @@ from sarj_python_lint.rule_base import (
|
|
|
14
14
|
RuleDocumentation,
|
|
15
15
|
RuleExample,
|
|
16
16
|
)
|
|
17
|
+
from sarj_python_lint.rules._ast_names import root_name as _root_name
|
|
17
18
|
from sarj_python_lint.rules._imports import ImportIndex
|
|
18
19
|
from sarj_python_lint.rules._paths import is_test_path
|
|
19
20
|
|
|
@@ -237,12 +238,6 @@ def _shadowed_in_enclosing_function(
|
|
|
237
238
|
return False
|
|
238
239
|
|
|
239
240
|
|
|
240
|
-
def _root_name(node: ast.expr) -> str | None:
|
|
241
|
-
while isinstance(node, ast.Attribute):
|
|
242
|
-
node = node.value
|
|
243
|
-
return node.id if isinstance(node, ast.Name) else None
|
|
244
|
-
|
|
245
|
-
|
|
246
241
|
def _function_binds(node: ast.FunctionDef | ast.AsyncFunctionDef | ast.Lambda, name: str) -> bool:
|
|
247
242
|
arguments = node.args
|
|
248
243
|
if (
|
{sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_partial_type_is.py
RENAMED
|
@@ -16,6 +16,7 @@ from sarj_python_lint.rule_base import (
|
|
|
16
16
|
Severity,
|
|
17
17
|
is_suppressed,
|
|
18
18
|
)
|
|
19
|
+
from sarj_python_lint.rules._closed_helpers import executable_body
|
|
19
20
|
from sarj_python_lint.rules._imports import TYPING_SOURCES
|
|
20
21
|
from sarj_python_lint.rules._type_guard_symbols import (
|
|
21
22
|
builtin_guard_symbol,
|
|
@@ -211,14 +212,7 @@ def _partial_return(function: ast.FunctionDef, context: PythonFileContext) -> as
|
|
|
211
212
|
|
|
212
213
|
|
|
213
214
|
def _single_return(function: ast.FunctionDef) -> ast.Return | None:
|
|
214
|
-
body = function
|
|
215
|
-
if (
|
|
216
|
-
body
|
|
217
|
-
and isinstance(body[0], ast.Expr)
|
|
218
|
-
and isinstance(body[0].value, ast.Constant)
|
|
219
|
-
and isinstance(body[0].value.value, str)
|
|
220
|
-
):
|
|
221
|
-
body = body[1:]
|
|
215
|
+
body = executable_body(function)
|
|
222
216
|
return body[0] if len(body) == 1 and isinstance(body[0], ast.Return) else None
|
|
223
217
|
|
|
224
218
|
|
|
@@ -951,14 +951,6 @@ def _scope_bindings(function: ast.FunctionDef | ast.AsyncFunctionDef) -> frozens
|
|
|
951
951
|
return frozenset(names)
|
|
952
952
|
|
|
953
953
|
|
|
954
|
-
def _target_names(node: ast.expr) -> set[str]:
|
|
955
|
-
if isinstance(node, ast.Name):
|
|
956
|
-
return {node.id}
|
|
957
|
-
if isinstance(node, ast.Tuple | ast.List):
|
|
958
|
-
return {name for element in node.elts for name in _target_names(element)}
|
|
959
|
-
return set()
|
|
960
|
-
|
|
961
|
-
|
|
962
954
|
def _position(node: ast.AST) -> AstPosition:
|
|
963
955
|
return ast_position(node, missing=-1)
|
|
964
956
|
|
|
@@ -20,6 +20,7 @@ from sarj_python_lint.rule_base import (
|
|
|
20
20
|
is_suppressed,
|
|
21
21
|
)
|
|
22
22
|
from sarj_python_lint.rules._ast_index import comprehension_results, walk as walk_ast
|
|
23
|
+
from sarj_python_lint.rules._ast_names import root_name as _root_name
|
|
23
24
|
from sarj_python_lint.rules._imports import ImportIndex
|
|
24
25
|
from sarj_python_lint.rules._paths import is_test_path
|
|
25
26
|
|
|
@@ -984,13 +985,6 @@ def _api_resolves(
|
|
|
984
985
|
return root is not None and root not in api.shadowed and api.imports.resolves(node, sources=sources, symbol=symbol)
|
|
985
986
|
|
|
986
987
|
|
|
987
|
-
def _root_name(node: ast.expr) -> str | None:
|
|
988
|
-
current = node
|
|
989
|
-
while isinstance(current, ast.Attribute):
|
|
990
|
-
current = current.value
|
|
991
|
-
return current.id if isinstance(current, ast.Name) else None
|
|
992
|
-
|
|
993
|
-
|
|
994
988
|
def _is_source_open(
|
|
995
989
|
node: ast.expr,
|
|
996
990
|
path_names: set[str],
|
{sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/no_select_star.py
RENAMED
|
@@ -17,6 +17,7 @@ from sarj_python_lint.rule_base import (
|
|
|
17
17
|
RuleExample,
|
|
18
18
|
)
|
|
19
19
|
from sarj_python_lint.rules._ast_index import walk
|
|
20
|
+
from sarj_python_lint.rules._ast_names import unqualified_name as _call_name
|
|
20
21
|
from sarj_python_lint.rules._paths import is_test_path
|
|
21
22
|
from sarj_python_lint.rules._sql import POSTGRES_UNQUOTED_IDENTIFIER, sql_string_value, strip_sql_noise
|
|
22
23
|
|
|
@@ -280,11 +281,3 @@ def _is_query_binding(target: ast.expr) -> bool:
|
|
|
280
281
|
name = target.id if isinstance(target, ast.Name) else target.attr
|
|
281
282
|
tokens = frozenset(part for part in name.lower().split("_") if part)
|
|
282
283
|
return name == "q" or name.isupper() or bool(tokens & _QUERY_BINDING_TOKENS)
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
def _call_name(function: ast.expr) -> str:
|
|
286
|
-
match function:
|
|
287
|
-
case ast.Name(id=name) | ast.Attribute(attr=name):
|
|
288
|
-
return name
|
|
289
|
-
case _:
|
|
290
|
-
return ""
|
|
@@ -16,6 +16,7 @@ from sarj_python_lint.rule_base import (
|
|
|
16
16
|
Severity,
|
|
17
17
|
is_suppressed,
|
|
18
18
|
)
|
|
19
|
+
from sarj_python_lint.rules._closed_helpers import executable_body
|
|
19
20
|
from sarj_python_lint.rules._imports import TYPING_SOURCES
|
|
20
21
|
from sarj_python_lint.rules._type_guard_symbols import (
|
|
21
22
|
builtin_guard_symbol,
|
|
@@ -197,14 +198,7 @@ def _guard_record(
|
|
|
197
198
|
|
|
198
199
|
|
|
199
200
|
def _single_return(function: ast.FunctionDef) -> ast.Return | None:
|
|
200
|
-
body = function
|
|
201
|
-
if (
|
|
202
|
-
body
|
|
203
|
-
and isinstance(body[0], ast.Expr)
|
|
204
|
-
and isinstance(body[0].value, ast.Constant)
|
|
205
|
-
and isinstance(body[0].value.value, str)
|
|
206
|
-
):
|
|
207
|
-
body = body[1:]
|
|
201
|
+
body = executable_body(function)
|
|
208
202
|
return body[0] if len(body) == 1 and isinstance(body[0], ast.Return) else None
|
|
209
203
|
|
|
210
204
|
|
|
@@ -16,6 +16,7 @@ from sarj_python_lint.rule_base import (
|
|
|
16
16
|
Severity,
|
|
17
17
|
is_suppressed,
|
|
18
18
|
)
|
|
19
|
+
from sarj_python_lint.rules._ast_names import terminal_name as _terminal_name
|
|
19
20
|
from sarj_python_lint.rules._prose_budget import groups
|
|
20
21
|
|
|
21
22
|
|
|
@@ -138,11 +139,3 @@ def _is_public_contract(node: ast.FunctionDef | ast.AsyncFunctionDef, parents: M
|
|
|
138
139
|
_terminal_name(base) in _PUBLIC_CONTRACT_BASES for base in owner.bases
|
|
139
140
|
)
|
|
140
141
|
return not decorators.isdisjoint(_PUBLIC_CONTRACT_DECORATORS) or protocol_method
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
def _terminal_name(node: ast.expr) -> str | None:
|
|
144
|
-
match node:
|
|
145
|
-
case ast.Name(id=name) | ast.Attribute(attr=name):
|
|
146
|
-
return name
|
|
147
|
-
case _:
|
|
148
|
-
return None
|
|
@@ -20,6 +20,7 @@ from sarj_python_lint.rule_base import (
|
|
|
20
20
|
Severity,
|
|
21
21
|
)
|
|
22
22
|
from sarj_python_lint.rules._ast_index import object_list, walk as walk_ast
|
|
23
|
+
from sarj_python_lint.rules._ast_names import expression_root as _root_name
|
|
23
24
|
from sarj_python_lint.rules._logging import LOG_METHODS, is_logger_expr
|
|
24
25
|
|
|
25
26
|
|
|
@@ -382,12 +383,6 @@ def _mutated_names(statement: ast.stmt) -> frozenset[str]:
|
|
|
382
383
|
return frozenset(names)
|
|
383
384
|
|
|
384
385
|
|
|
385
|
-
def _root_name(node: ast.expr) -> str | None:
|
|
386
|
-
while isinstance(node, (ast.Attribute, ast.Subscript)):
|
|
387
|
-
node = node.value
|
|
388
|
-
return node.id if isinstance(node, ast.Name) else None
|
|
389
|
-
|
|
390
|
-
|
|
391
386
|
def _containing_statement(node: ast.AST, parents: Mapping[ast.AST, ast.AST]) -> ast.stmt | None:
|
|
392
387
|
current: ast.AST | None = node
|
|
393
388
|
while current is not None and not isinstance(current, ast.stmt):
|
{sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/over_mocked_test.py
RENAMED
|
@@ -16,6 +16,7 @@ from sarj_python_lint.rule_base import (
|
|
|
16
16
|
RuleExample,
|
|
17
17
|
Severity,
|
|
18
18
|
)
|
|
19
|
+
from sarj_python_lint.rules._ast_names import dotted_name as _dotted
|
|
19
20
|
from sarj_python_lint.rules._paths import is_test_path
|
|
20
21
|
|
|
21
22
|
|
|
@@ -809,18 +810,6 @@ def _joined_text(node: ast.JoinedStr) -> str:
|
|
|
809
810
|
return "".join(parts)
|
|
810
811
|
|
|
811
812
|
|
|
812
|
-
def _dotted(node: ast.expr) -> str | None:
|
|
813
|
-
parts: list[str] = []
|
|
814
|
-
current = node
|
|
815
|
-
while isinstance(current, ast.Attribute):
|
|
816
|
-
parts.append(current.attr)
|
|
817
|
-
current = current.value
|
|
818
|
-
if not isinstance(current, ast.Name):
|
|
819
|
-
return None
|
|
820
|
-
parts.append(current.id)
|
|
821
|
-
return ".".join(reversed(parts))
|
|
822
|
-
|
|
823
|
-
|
|
824
813
|
def _collect_parametrized_names(argnames: ast.expr | None, parametrized: set[str]) -> None:
|
|
825
814
|
if isinstance(argnames, ast.Constant) and isinstance(argnames.value, str):
|
|
826
815
|
parametrized.update(stripped_name for name in argnames.value.split(",") if (stripped_name := name.strip()))
|
{sarj_python_lint-1.66.0 → sarj_python_lint-1.66.1}/src/sarj_python_lint/rules/prefer_class_row.py
RENAMED
|
@@ -16,6 +16,7 @@ from sarj_python_lint.rule_base import (
|
|
|
16
16
|
Severity,
|
|
17
17
|
)
|
|
18
18
|
from sarj_python_lint.rules._ast_index import walk as walk_ast
|
|
19
|
+
from sarj_python_lint.rules._ast_names import expression_root as _target_root
|
|
19
20
|
from sarj_python_lint.rules._paths import is_test_path
|
|
20
21
|
|
|
21
22
|
|
|
@@ -466,12 +467,6 @@ def _writes_name(node: ast.stmt, name: str) -> bool:
|
|
|
466
467
|
return any(_target_root(target) == name for target in targets)
|
|
467
468
|
|
|
468
469
|
|
|
469
|
-
def _target_root(node: ast.expr) -> str | None:
|
|
470
|
-
while isinstance(node, (ast.Attribute, ast.Subscript)):
|
|
471
|
-
node = node.value
|
|
472
|
-
return node.id if isinstance(node, ast.Name) else None
|
|
473
|
-
|
|
474
|
-
|
|
475
470
|
def _dotted(node: ast.expr) -> str | None:
|
|
476
471
|
parts: list[str] = []
|
|
477
472
|
while isinstance(node, ast.Attribute):
|
|
@@ -4,10 +4,8 @@ import ast
|
|
|
4
4
|
from collections import defaultdict
|
|
5
5
|
from dataclasses import dataclass
|
|
6
6
|
from enum import StrEnum
|
|
7
|
-
from io import StringIO
|
|
8
7
|
from itertools import pairwise
|
|
9
8
|
from pathlib import PurePosixPath
|
|
10
|
-
import tokenize
|
|
11
9
|
from typing import TYPE_CHECKING, ClassVar, final, override
|
|
12
10
|
|
|
13
11
|
from sarj_python_lint.rule_base import (
|
|
@@ -23,6 +21,7 @@ from sarj_python_lint.rule_base import (
|
|
|
23
21
|
is_suppressed,
|
|
24
22
|
)
|
|
25
23
|
from sarj_python_lint.rules._ast_index import children, walk as walk_ast
|
|
24
|
+
from sarj_python_lint.rules._comments import comment_line_numbers
|
|
26
25
|
|
|
27
26
|
|
|
28
27
|
if TYPE_CHECKING:
|
|
@@ -243,7 +242,6 @@ class PreferCollectionComprehension(Rule):
|
|
|
243
242
|
@override
|
|
244
243
|
def check_context(self, context: PythonFileContext) -> list[Diagnostic]:
|
|
245
244
|
path = context.path
|
|
246
|
-
source = context.source
|
|
247
245
|
if context.generated:
|
|
248
246
|
return []
|
|
249
247
|
tree = context.tree
|
|
@@ -251,7 +249,7 @@ class PreferCollectionComprehension(Rule):
|
|
|
251
249
|
return []
|
|
252
250
|
|
|
253
251
|
source_lines = context.source_lines
|
|
254
|
-
comments =
|
|
252
|
+
comments = comment_line_numbers(context.source)
|
|
255
253
|
diagnostics: list[Diagnostic] = []
|
|
256
254
|
set_shadowed = _set_is_shadowed(tree, node_index=context.node_index)
|
|
257
255
|
namespace_observers = _namespace_observer_calls(context)
|
|
@@ -834,14 +832,6 @@ def _replacement_fits(init: _Init, name: str, expression: str, *, allow_multilin
|
|
|
834
832
|
)
|
|
835
833
|
|
|
836
834
|
|
|
837
|
-
def _comment_lines(source: str) -> frozenset[int]:
|
|
838
|
-
try:
|
|
839
|
-
tokens = tokenize.generate_tokens(StringIO(source).readline)
|
|
840
|
-
return frozenset(token.start[0] for token in tokens if token.type == tokenize.COMMENT)
|
|
841
|
-
except IndentationError, tokenize.TokenError:
|
|
842
|
-
return frozenset()
|
|
843
|
-
|
|
844
|
-
|
|
845
835
|
def _has_comment(init: _Init, loop: ast.For, comments: frozenset[int]) -> bool:
|
|
846
836
|
end_line = loop.end_lineno or loop.lineno
|
|
847
837
|
return any(init.lineno <= line <= end_line for line in comments)
|