sarj-python-lint 1.10.0__tar.gz → 1.10.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.10.0 → sarj_python_lint-1.10.1}/PKG-INFO +1 -1
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/pyproject.toml +1 -1
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_injected_module_loader.py +120 -26
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/.gitignore +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/LICENSE +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/README.md +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/__init__.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/__main__.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/_analysis_session.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/_file_context.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/_filesystem.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/_python_target.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/_ratchet_cli.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/_secret_names.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/_version.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/benchmark.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/json_boundary.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/py.typed +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/ratchet.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rule_base.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/__init__.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_ast_index.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_ast_position.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_comments.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_docstrings.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_fastapi.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_first_party.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_imports.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_logging.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_paths.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_project_index.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_pytest.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_registry.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_set_fields.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_sql.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_test_composition.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/discourage_nullable_constructor_parameters.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_database_programmability.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_select_star.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/stepdown.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
- {sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/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.10.
|
|
3
|
+
Version: 1.10.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/
|
|
@@ -20,12 +20,23 @@ from sarj_python_lint.rules.no_hidden_constructor_fallback import LocalBindingCo
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
if TYPE_CHECKING:
|
|
23
|
-
from collections.abc import Iterator
|
|
23
|
+
from collections.abc import Iterator, Mapping
|
|
24
24
|
|
|
25
25
|
from sarj_python_lint._file_context import PythonFileContext
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
_LOADER_TARGETS = frozenset({"importlib.import_module", "importlib.__import__", "builtins.__import__"})
|
|
29
|
+
_LEXICAL_SCOPES = (
|
|
30
|
+
ast.Module,
|
|
31
|
+
ast.FunctionDef,
|
|
32
|
+
ast.AsyncFunctionDef,
|
|
33
|
+
ast.ClassDef,
|
|
34
|
+
ast.Lambda,
|
|
35
|
+
ast.ListComp,
|
|
36
|
+
ast.SetComp,
|
|
37
|
+
ast.DictComp,
|
|
38
|
+
ast.GeneratorExp,
|
|
39
|
+
)
|
|
29
40
|
|
|
30
41
|
|
|
31
42
|
@final
|
|
@@ -42,7 +53,8 @@ class NoInjectedModuleLoader(Rule):
|
|
|
42
53
|
limitations=(
|
|
43
54
|
"Flags defaults resolving to importlib.import_module, importlib.__import__, or builtins.__import__, including stable module-level import and single-assignment aliases and unshadowed __import__.",
|
|
44
55
|
"Tests, test support, and generated code are excluded. Required loader parameters, application loaders, wrapper lambdas, alias chains, comprehensions, and imports local to enclosing scopes are not inferred.",
|
|
45
|
-
"Conservatively skips shadowed or rebound names, wildcard-import files, and
|
|
56
|
+
"Conservatively skips shadowed or rebound names, wildcard-import files, reassigned loader attributes, and exception or pattern captures of importer roots, symbols or assignment aliases. A relevant-name capture in an unrelated local scope can cause a false negative because capture checks are file-wide.",
|
|
57
|
+
"Assignment aliases require one module binding and precede use by line and column. Defaults use their enclosing evaluation scope: earlier statements in the nearest executing class body can shadow loaders; methods and nested classes do not close over class attributes. Enclosing function body bindings remain conservative exclusions, but a function's parameters do not shadow its own defaults. Relevant global declarations and walrus writes exclude sensitive importer names. Compound class statements can cause conservative omissions. Dynamic namespace mutation is not inferred. No autofix: changing arguments or import placement can alter API and initialization behavior.",
|
|
46
58
|
),
|
|
47
59
|
examples=(
|
|
48
60
|
RuleExample(
|
|
@@ -83,15 +95,21 @@ class NoInjectedModuleLoader(Rule):
|
|
|
83
95
|
or context.generated
|
|
84
96
|
or is_test_path(context.path)
|
|
85
97
|
or is_test_support_path(context.path)
|
|
86
|
-
or _ambiguous_loader_bindings(context)
|
|
87
98
|
):
|
|
88
99
|
return []
|
|
89
100
|
aliases = _stable_loader_aliases(context)
|
|
101
|
+
if _ambiguous_loader_bindings(context, aliases):
|
|
102
|
+
return []
|
|
90
103
|
findings: list[Diagnostic] = []
|
|
91
104
|
for function in context.nodes(ast.FunctionDef, ast.AsyncFunctionDef, ast.Lambda):
|
|
92
105
|
for argument, default in _defaults(function.args):
|
|
93
106
|
direct = _is_loader(default, context)
|
|
94
|
-
aliased =
|
|
107
|
+
aliased = (
|
|
108
|
+
isinstance(default, ast.Name)
|
|
109
|
+
and default.id in aliases
|
|
110
|
+
and (aliases[default.id].lineno, aliases[default.id].col_offset)
|
|
111
|
+
< (function.lineno, function.col_offset)
|
|
112
|
+
)
|
|
95
113
|
if not (direct or aliased) or _shadowed(default, function, context):
|
|
96
114
|
continue
|
|
97
115
|
findings.append(
|
|
@@ -107,9 +125,28 @@ class NoInjectedModuleLoader(Rule):
|
|
|
107
125
|
return sorted(findings, key=lambda finding: (finding.line, finding.col))
|
|
108
126
|
|
|
109
127
|
|
|
110
|
-
def _ambiguous_loader_bindings(context: PythonFileContext) -> bool:
|
|
128
|
+
def _ambiguous_loader_bindings(context: PythonFileContext, aliases: Mapping[str, ast.stmt]) -> bool:
|
|
111
129
|
if any(alias.name == "*" for node in context.nodes(ast.ImportFrom) for alias in node.names):
|
|
112
130
|
return True
|
|
131
|
+
sensitive_names = {"__import__", *aliases} | {
|
|
132
|
+
name
|
|
133
|
+
for name, target in context.module_imports.bindings.items()
|
|
134
|
+
if (target.module in {"importlib", "builtins"} and target.symbol is None)
|
|
135
|
+
or f"{target.module}.{target.symbol}" in _LOADER_TARGETS
|
|
136
|
+
}
|
|
137
|
+
if any(sensitive_names.intersection(node.names) for node in context.nodes(ast.Global)):
|
|
138
|
+
return True
|
|
139
|
+
for node in context.nodes(ast.ExceptHandler, ast.MatchAs, ast.MatchStar, ast.MatchMapping, ast.NamedExpr):
|
|
140
|
+
match node:
|
|
141
|
+
case (
|
|
142
|
+
ast.ExceptHandler(name=name)
|
|
143
|
+
| ast.MatchAs(name=name)
|
|
144
|
+
| ast.MatchStar(name=name)
|
|
145
|
+
| ast.MatchMapping(rest=name)
|
|
146
|
+
| ast.NamedExpr(target=ast.Name(id=name))
|
|
147
|
+
):
|
|
148
|
+
if name in sensitive_names:
|
|
149
|
+
return True
|
|
113
150
|
return any(
|
|
114
151
|
isinstance(node.ctx, (ast.Store, ast.Del))
|
|
115
152
|
and context.module_imports.resolved_qualified_name(node) in _LOADER_TARGETS
|
|
@@ -144,27 +181,51 @@ def _shadowed(default: ast.expr, function: ast.AST, context: PythonFileContext)
|
|
|
144
181
|
root = root.value
|
|
145
182
|
if not isinstance(root, ast.Name):
|
|
146
183
|
return True
|
|
147
|
-
|
|
184
|
+
child = function
|
|
185
|
+
parent = context.parents.get(child)
|
|
186
|
+
class_scope_visible = True
|
|
148
187
|
while parent is not None:
|
|
149
188
|
if isinstance(parent, (ast.ListComp, ast.SetComp, ast.DictComp, ast.GeneratorExp)):
|
|
150
189
|
return True
|
|
151
190
|
if isinstance(parent, (ast.FunctionDef, ast.AsyncFunctionDef, ast.Lambda)):
|
|
152
|
-
if
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if root.id in collector.names:
|
|
191
|
+
if _in_scope_body(parent, child):
|
|
192
|
+
if root.id in scope_bindings(parent):
|
|
193
|
+
return True
|
|
194
|
+
class_scope_visible = False
|
|
195
|
+
elif isinstance(parent, ast.ClassDef) and _in_scope_body(parent, child):
|
|
196
|
+
if class_scope_visible and _class_prefix_shadows(parent, child, root.id):
|
|
159
197
|
return True
|
|
198
|
+
class_scope_visible = False
|
|
199
|
+
child = parent
|
|
160
200
|
parent = context.parents.get(parent)
|
|
161
201
|
return False
|
|
162
202
|
|
|
163
203
|
|
|
164
|
-
def
|
|
204
|
+
def _in_scope_body(scope: ast.FunctionDef | ast.AsyncFunctionDef | ast.ClassDef | ast.Lambda, child: ast.AST) -> bool:
|
|
205
|
+
# Defaults and class headers execute outside the scope being defined.
|
|
206
|
+
return scope.body is child if isinstance(scope, ast.Lambda) else child in scope.body
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _class_prefix_shadows(owner: ast.ClassDef, containing: ast.AST, name: str) -> bool:
|
|
210
|
+
collector = LocalBindingCollector()
|
|
211
|
+
for statement in owner.body:
|
|
212
|
+
if statement is containing:
|
|
213
|
+
match statement:
|
|
214
|
+
case ast.Assign(value=value) | ast.AnnAssign(value=ast.expr() as value):
|
|
215
|
+
collector.visit(value)
|
|
216
|
+
case ast.FunctionDef() | ast.AsyncFunctionDef() | ast.ClassDef():
|
|
217
|
+
pass
|
|
218
|
+
case _:
|
|
219
|
+
collector.visit(statement)
|
|
220
|
+
break
|
|
221
|
+
collector.visit(statement)
|
|
222
|
+
return name in collector.names
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _stable_loader_aliases(context: PythonFileContext) -> dict[str, ast.stmt]:
|
|
165
226
|
if context.tree is None:
|
|
166
227
|
return {}
|
|
167
|
-
aliases: dict[str,
|
|
228
|
+
aliases: dict[str, ast.stmt] = {}
|
|
168
229
|
for statement in context.tree.body:
|
|
169
230
|
match statement:
|
|
170
231
|
case (
|
|
@@ -173,16 +234,16 @@ def _stable_loader_aliases(context: PythonFileContext) -> dict[str, int]:
|
|
|
173
234
|
):
|
|
174
235
|
if (
|
|
175
236
|
_is_loader(value, context)
|
|
176
|
-
and _loader_import_precedes(value, statement
|
|
237
|
+
and _loader_import_precedes(value, statement, context)
|
|
177
238
|
and _binding_count(name, context) == 1
|
|
178
239
|
):
|
|
179
|
-
aliases[name] = statement
|
|
240
|
+
aliases[name] = statement
|
|
180
241
|
case _:
|
|
181
242
|
pass
|
|
182
243
|
return aliases
|
|
183
244
|
|
|
184
245
|
|
|
185
|
-
def _loader_import_precedes(value: ast.expr,
|
|
246
|
+
def _loader_import_precedes(value: ast.expr, assignment: ast.stmt, context: PythonFileContext) -> bool:
|
|
186
247
|
root = value
|
|
187
248
|
while isinstance(root, ast.Attribute):
|
|
188
249
|
root = root.value
|
|
@@ -191,7 +252,7 @@ def _loader_import_precedes(value: ast.expr, line: int, context: PythonFileConte
|
|
|
191
252
|
if root.id == "__import__" and context.module_imports.builtin_is_unshadowed(root.id):
|
|
192
253
|
return True
|
|
193
254
|
return any(
|
|
194
|
-
statement.lineno <
|
|
255
|
+
(statement.lineno, statement.col_offset) < (assignment.lineno, assignment.col_offset)
|
|
195
256
|
and any((alias.asname or alias.name.split(".")[0]) == root.id for alias in statement.names)
|
|
196
257
|
for statement in context.tree.body
|
|
197
258
|
if isinstance(statement, (ast.Import, ast.ImportFrom))
|
|
@@ -200,14 +261,47 @@ def _loader_import_precedes(value: ast.expr, line: int, context: PythonFileConte
|
|
|
200
261
|
|
|
201
262
|
def _binding_count(name: str, context: PythonFileContext) -> int:
|
|
202
263
|
return (
|
|
203
|
-
sum(
|
|
204
|
-
|
|
205
|
-
+ sum((node.asname or node.name.split(".")[0]) == name for node in context.nodes(ast.alias))
|
|
206
|
-
+ sum(
|
|
207
|
-
node.name == name
|
|
264
|
+
sum(
|
|
265
|
+
_binds_name(node, name) and _is_module_binding(node, context)
|
|
208
266
|
for node in context.nodes(
|
|
209
|
-
ast.
|
|
267
|
+
ast.Name,
|
|
268
|
+
ast.alias,
|
|
269
|
+
ast.FunctionDef,
|
|
270
|
+
ast.AsyncFunctionDef,
|
|
271
|
+
ast.ClassDef,
|
|
272
|
+
ast.ExceptHandler,
|
|
273
|
+
ast.MatchAs,
|
|
274
|
+
ast.MatchStar,
|
|
275
|
+
ast.MatchMapping,
|
|
210
276
|
)
|
|
211
277
|
)
|
|
212
|
-
+ sum(node.
|
|
278
|
+
+ sum(name in node.names for node in context.nodes(ast.Global))
|
|
279
|
+
+ sum(node.target.id == name for node in context.nodes(ast.NamedExpr))
|
|
213
280
|
)
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def _binds_name(node: ast.AST, name: str) -> bool:
|
|
284
|
+
match node:
|
|
285
|
+
case (
|
|
286
|
+
ast.Name(id=bound, ctx=(ast.Store() | ast.Del()))
|
|
287
|
+
| ast.FunctionDef(name=bound)
|
|
288
|
+
| ast.AsyncFunctionDef(name=bound)
|
|
289
|
+
| ast.ClassDef(name=bound)
|
|
290
|
+
| ast.ExceptHandler(name=bound)
|
|
291
|
+
| ast.MatchAs(name=bound)
|
|
292
|
+
| ast.MatchStar(name=bound)
|
|
293
|
+
| ast.MatchMapping(rest=bound)
|
|
294
|
+
):
|
|
295
|
+
return bound == name
|
|
296
|
+
case ast.alias(name=imported, asname=alias):
|
|
297
|
+
return (alias or imported.partition(".")[0]) == name
|
|
298
|
+
case _:
|
|
299
|
+
return False
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def _is_module_binding(node: ast.AST, context: PythonFileContext) -> bool:
|
|
303
|
+
while node in context.parents:
|
|
304
|
+
node = context.parents[node]
|
|
305
|
+
if isinstance(node, _LEXICAL_SCOPES):
|
|
306
|
+
return isinstance(node, ast.Module)
|
|
307
|
+
return False
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/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
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_ast_index.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_ast_position.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_dict_key_views.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_docstrings.py
RENAMED
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_first_party.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_fixed_record.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_nominal_project.py
RENAMED
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_project_index.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/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.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_set_fields.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_test_assertions.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/_test_composition.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
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/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
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/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.10.0 → sarj_python_lint-1.10.1}/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
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/no_secret_in_log.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/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
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/over_mocked_test.py
RENAMED
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/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
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/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
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/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
|
{sarj_python_lint-1.10.0 → sarj_python_lint-1.10.1}/src/sarj_python_lint/rules/unused_mock_setup.py
RENAMED
|
File without changes
|
|
File without changes
|