sarj-python-lint 1.25.4__tar.gz → 1.25.5__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.25.4 → sarj_python_lint-1.25.5}/PKG-INFO +1 -1
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/pyproject.toml +1 -1
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_tautological_expect.py +118 -2
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/.gitignore +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/LICENSE +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/README.md +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/__init__.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/__main__.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/_analysis_session.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/_file_context.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/_filesystem.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/_python_target.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/_ratchet_cli.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/_secret_names.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/_source.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/_version.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/benchmark.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/json_boundary.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/py.typed +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/ratchet.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rule_base.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/__init__.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_ast_index.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_ast_position.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_comments.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_copy_on_write.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_docstrings.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_fastapi.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_first_party.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_imports.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_local_source.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_logging.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_paths.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_project_index.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_pytest.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_registry.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_set_fields.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_sql.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_test_composition.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_test_provenance.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_before_validator_input_mutation.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_broad_keyword_capture.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_injected_module_loader.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_input_model_mutation.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_mocked_pydantic_value_object.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_select_star.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_shallow_container_type_guard.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_test_method_grafting.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_unused_copy_result.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_unused_underscored_keyword_parameter.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_autospec_for_callable_mock.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_native_string_check.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_pytest_fixture_injection.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_required_constructor_parameters.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/require_precise_factory_signature.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/stepdown.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
- {sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/unused_test_factory_option.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sarj-python-lint
|
|
3
|
-
Version: 1.25.
|
|
3
|
+
Version: 1.25.5
|
|
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/
|
|
@@ -15,6 +15,7 @@ from sarj_python_lint.rule_base import (
|
|
|
15
15
|
Severity,
|
|
16
16
|
)
|
|
17
17
|
from sarj_python_lint.rules._ast_index import walk as walk_ast
|
|
18
|
+
from sarj_python_lint.rules._paths import is_test_path
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
if TYPE_CHECKING:
|
|
@@ -32,13 +33,14 @@ _FAIL = "fail"
|
|
|
32
33
|
|
|
33
34
|
# Enough of the operand to identify it in the message without pasting a screenful.
|
|
34
35
|
_OPERAND_PREVIEW_CHARS = 40
|
|
36
|
+
_UNKNOWN = object()
|
|
35
37
|
|
|
36
38
|
|
|
37
39
|
class NoTautologicalExpect(Rule):
|
|
38
40
|
id: str = "no-statically-truthy-assertion"
|
|
39
41
|
code: str = "SARJ057"
|
|
40
42
|
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
41
|
-
summary="
|
|
43
|
+
summary="An assertion condition is statically truthy, including test-local scalar setup.",
|
|
42
44
|
rationale=(
|
|
43
45
|
"A condition that stays truthy whenever evaluation succeeds cannot reject an incorrect result and often "
|
|
44
46
|
"means the intended condition was wrapped in a container or placed in the message slot."
|
|
@@ -51,10 +53,40 @@ class NoTautologicalExpect(Rule):
|
|
|
51
53
|
aliases=("no-tautological-expect",),
|
|
52
54
|
limitations=(
|
|
53
55
|
"Detection covers truthy scalar constants and definitely non-empty list, set, and dict displays.",
|
|
56
|
+
"Test-local immutable scalar bindings and their aliases are tracked only through straight-line assignments; calls, control flow, mutable values, and global/nonlocal writes invalidate tracking.",
|
|
54
57
|
"Ruff owns asserted strings and tuples, literal comparisons and identity, and unittest-style assertion methods.",
|
|
55
58
|
"Generated files, always-failing assertions, deliberate match-arm success markers, and runtime-value comparisons are excluded.",
|
|
56
59
|
),
|
|
57
60
|
examples=(
|
|
61
|
+
RuleExample(
|
|
62
|
+
example_id="setup-only-oracle",
|
|
63
|
+
scenario="setup-only",
|
|
64
|
+
title="A test asserts only on its own fixed setup",
|
|
65
|
+
outcome=ExampleOutcome.MATCH,
|
|
66
|
+
files=(
|
|
67
|
+
ExampleFile.python(
|
|
68
|
+
"tests/test_service.py", "def test_service():\n status = 'ok'\n assert status == 'ok'\n"
|
|
69
|
+
),
|
|
70
|
+
),
|
|
71
|
+
focus_path=PurePosixPath("tests/test_service.py"),
|
|
72
|
+
expected_count=1,
|
|
73
|
+
public=True,
|
|
74
|
+
),
|
|
75
|
+
RuleExample(
|
|
76
|
+
example_id="produced-scalar-oracle",
|
|
77
|
+
scenario="setup-only",
|
|
78
|
+
title="Assert on a value returned by the application",
|
|
79
|
+
outcome=ExampleOutcome.NO_MATCH,
|
|
80
|
+
files=(
|
|
81
|
+
ExampleFile.python(
|
|
82
|
+
"tests/test_service.py",
|
|
83
|
+
"def test_service():\n status = service_status()\n assert status == 'ok'\n",
|
|
84
|
+
),
|
|
85
|
+
),
|
|
86
|
+
focus_path=PurePosixPath("tests/test_service.py"),
|
|
87
|
+
expected_count=0,
|
|
88
|
+
public=True,
|
|
89
|
+
),
|
|
58
90
|
RuleExample(
|
|
59
91
|
example_id="condition-in-message-slot",
|
|
60
92
|
title="The intended condition became an assertion message",
|
|
@@ -96,6 +128,9 @@ class NoTautologicalExpect(Rule):
|
|
|
96
128
|
if tree is None:
|
|
97
129
|
return []
|
|
98
130
|
exempt = _exempt_nodes(tree, node_index=context.node_index)
|
|
131
|
+
tautologies = _tautologies(tree, exempt, node_index=context.node_index)
|
|
132
|
+
if is_test_path(path) and path.name != "conftest.py":
|
|
133
|
+
tautologies.extend(_bound_tautologies(context))
|
|
99
134
|
diags = [
|
|
100
135
|
Diagnostic(
|
|
101
136
|
path=path,
|
|
@@ -105,12 +140,93 @@ class NoTautologicalExpect(Rule):
|
|
|
105
140
|
message=_message(node, reason),
|
|
106
141
|
severity=Severity.ERROR,
|
|
107
142
|
)
|
|
108
|
-
for node, reason in
|
|
143
|
+
for node, reason in tautologies
|
|
109
144
|
]
|
|
110
145
|
diags.sort(key=lambda d: (d.line, d.col))
|
|
111
146
|
return diags
|
|
112
147
|
|
|
113
148
|
|
|
149
|
+
def _bound_tautologies(context: PythonFileContext) -> list[_Tautology]:
|
|
150
|
+
found: list[_Tautology] = []
|
|
151
|
+
external_writes = context.nodes(ast.Global, ast.Nonlocal)
|
|
152
|
+
for function in context.nodes(ast.FunctionDef, ast.AsyncFunctionDef):
|
|
153
|
+
if not function.name.startswith("test_"):
|
|
154
|
+
continue
|
|
155
|
+
if any(function.lineno <= node.lineno <= (function.end_lineno or function.lineno) for node in external_writes):
|
|
156
|
+
continue
|
|
157
|
+
found.extend(_function_bound_tautologies(function))
|
|
158
|
+
return found
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def _function_bound_tautologies(function: ast.FunctionDef | ast.AsyncFunctionDef) -> list[_Tautology]:
|
|
162
|
+
found: list[_Tautology] = []
|
|
163
|
+
bindings: dict[str, object] = {}
|
|
164
|
+
for statement in function.body:
|
|
165
|
+
if _record_scalar_assignment(statement, bindings):
|
|
166
|
+
continue
|
|
167
|
+
if isinstance(statement, ast.Assert):
|
|
168
|
+
references_setup = any(
|
|
169
|
+
isinstance(node, ast.Name) and node.id in bindings for node in ast.walk(statement.test)
|
|
170
|
+
)
|
|
171
|
+
if references_setup and _scalar_condition(statement.test, bindings) is True:
|
|
172
|
+
found.append(_Tautology(statement, "the condition follows only from unchanged scalar setup"))
|
|
173
|
+
bindings.clear()
|
|
174
|
+
return found
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _record_scalar_assignment(statement: ast.stmt, bindings: dict[str, object]) -> bool:
|
|
178
|
+
match statement:
|
|
179
|
+
case (
|
|
180
|
+
ast.Assign(targets=[ast.Name(id=name)], value=value) | ast.AnnAssign(target=ast.Name(id=name), value=value)
|
|
181
|
+
) if value is not None:
|
|
182
|
+
scalar = _scalar_value(value, bindings)
|
|
183
|
+
if scalar is not _UNKNOWN:
|
|
184
|
+
bindings[name] = scalar
|
|
185
|
+
return True
|
|
186
|
+
case _:
|
|
187
|
+
pass
|
|
188
|
+
return False
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _scalar_value(node: ast.expr, bindings: dict[str, object]) -> object:
|
|
192
|
+
if isinstance(node, ast.Name):
|
|
193
|
+
return bindings.get(node.id, _UNKNOWN)
|
|
194
|
+
if isinstance(node, ast.Constant):
|
|
195
|
+
value: object = node.value
|
|
196
|
+
return value if value is None or isinstance(value, (bool, int, float, str, bytes)) else _UNKNOWN
|
|
197
|
+
if isinstance(node, ast.UnaryOp):
|
|
198
|
+
value = _scalar_value(node.operand, bindings)
|
|
199
|
+
if isinstance(node.op, ast.Not) and value is not _UNKNOWN:
|
|
200
|
+
return not value
|
|
201
|
+
if isinstance(value, (int, float)):
|
|
202
|
+
if isinstance(node.op, ast.USub):
|
|
203
|
+
return -value
|
|
204
|
+
if isinstance(node.op, ast.UAdd):
|
|
205
|
+
return +value
|
|
206
|
+
return _UNKNOWN
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _scalar_condition(node: ast.expr, bindings: dict[str, object]) -> bool | None:
|
|
210
|
+
if isinstance(node, ast.Compare) and len(node.ops) == 1:
|
|
211
|
+
left = _scalar_value(node.left, bindings)
|
|
212
|
+
right = _scalar_value(node.comparators[0], bindings)
|
|
213
|
+
if left is _UNKNOWN or right is _UNKNOWN:
|
|
214
|
+
return None
|
|
215
|
+
match node.ops[0]:
|
|
216
|
+
case ast.Eq():
|
|
217
|
+
return left == right
|
|
218
|
+
case ast.NotEq():
|
|
219
|
+
return left != right
|
|
220
|
+
case ast.Is() if left is None or isinstance(left, bool):
|
|
221
|
+
return left is right
|
|
222
|
+
case ast.IsNot() if left is None or isinstance(left, bool):
|
|
223
|
+
return left is not right
|
|
224
|
+
case _:
|
|
225
|
+
return None
|
|
226
|
+
value = _scalar_value(node, bindings)
|
|
227
|
+
return None if value is _UNKNOWN else bool(value)
|
|
228
|
+
|
|
229
|
+
|
|
114
230
|
def _exempt_nodes(tree: ast.Module, *, node_index: NodeIndex | None = None) -> set[ast.AST]:
|
|
115
231
|
exempt: set[ast.AST] = set()
|
|
116
232
|
for node in walk_ast(tree, index=node_index):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/_analysis_session.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_ast_index.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_ast_position.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_copy_on_write.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_dict_key_views.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_docstrings.py
RENAMED
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_first_party.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_fixed_record.py
RENAMED
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_local_source.py
RENAMED
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_nominal_project.py
RENAMED
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_project_index.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_prose_budget.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_set_fields.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_test_assertions.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_test_composition.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/_test_provenance.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/mock_without_spec.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_comment_cruft.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_dunder_all.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_secret_in_log.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/no_select_star.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/over_mocked_test.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_class_row.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_or_pattern.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/prefer_str_enum.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.25.4 → sarj_python_lint-1.25.5}/src/sarj_python_lint/rules/unused_mock_setup.py
RENAMED
|
File without changes
|
|
File without changes
|