sarj-python-lint 1.9.0__tar.gz → 1.9.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.9.0 → sarj_python_lint-1.9.1}/PKG-INFO +1 -1
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/pyproject.toml +1 -1
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_registry.py +2 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_sql.py +16 -2
- sarj_python_lint-1.9.1/src/sarj_python_lint/rules/no_database_programmability.py +118 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/.gitignore +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/LICENSE +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/README.md +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/__init__.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/__main__.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/_analysis_session.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/_file_context.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/_filesystem.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/_python_target.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/_ratchet_cli.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/_secret_names.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/_version.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/benchmark.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/json_boundary.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/py.typed +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/ratchet.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rule_base.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/__init__.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_annotation_semantics.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_ast_index.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_ast_position.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_comments.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_contract_annotation.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_dict_key_views.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_docstrings.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_fastapi.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_first_party.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_fixed_record.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_imports.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_logging.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_nominal_project.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_paths.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_project_index.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_pytest.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_resource_provenance.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_set_fields.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_test_composition.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/async_cleanup_registered_synchronously.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/async_mock_call_without_await_assertion.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/complex_postgres_query_requires_architecture_review.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/defect_xfail_requires_explicit_strict.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/discourage_nullable_constructor_parameters.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/excessive_commentary.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/fakes_in_shared_location.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/fastapi_class_router_contract.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/fastapi_explicit_openapi_contract.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/named_record_at_boundaries.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_analytical_aggregation_in_postgres_store.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_any_mapping_types.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_copied_inherited_docstring.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_delete_statement.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_dunder_all.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_excessive_cognitive_complexity.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_fastapi_on_event.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_file_level_escape_hatch_suppression.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_fixed_sleep_before_assert.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_invalid_argument_name_suppression.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_nullable_dependency_fallback.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_positional_psycopg_row_escape.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_psycopg_execution_outside_injected_owner.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_random_uuid_in_sql.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_raw_connection_in_tests.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_raw_source_text_test_oracle.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_redundant_module_alias_exports.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_repeated_test_body.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_select_star.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_service_behavior_in_settings.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_swallowed_asyncio_cancellation.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_unused_value_marker.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_whole_request_response_payload_in_log.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_collection_comprehension.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_injected_dependency_over_monkeypatch.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_match_exception_dispatch.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_match_value_dispatch.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_monkeypatch_for_process_state_in_test.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_monotonic_for_elapsed_time.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_pydantic_json_value.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_regex_fullmatch.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_set_isdisjoint.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_walrus_awaited_none_guard.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/pytest_fixture_returns_bare_tuple.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/repeated_kwarg_heavy_call_in_test.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/repeated_test_composition.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/require_explicit_contract_implementation.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/require_explicit_psycopg_transaction.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/require_explicit_service_contract.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/require_public_dependency_contract.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/require_pydantic_for_structured_payload.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/shared_mutable_pydantic_factory.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/stepdown.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/store_get_delegates_to_bulk_read.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/subprocess_kill_without_reap.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/timestamp_order_requires_tiebreaker.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/typed_error_reasons.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
- {sarj_python_lint-1.9.0 → sarj_python_lint-1.9.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.9.
|
|
3
|
+
Version: 1.9.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/
|
|
@@ -39,6 +39,7 @@ from sarj_python_lint.rules.no_copied_inherited_docstring import NoCopiedInherit
|
|
|
39
39
|
from sarj_python_lint.rules.no_cors_wildcard_with_credentials import (
|
|
40
40
|
NoCorsWildcardWithCredentials,
|
|
41
41
|
)
|
|
42
|
+
from sarj_python_lint.rules.no_database_programmability import NoDatabaseProgrammability
|
|
42
43
|
from sarj_python_lint.rules.no_delete_statement import NoDeleteStatement
|
|
43
44
|
from sarj_python_lint.rules.no_dunder_all import NoDunderAll
|
|
44
45
|
from sarj_python_lint.rules.no_duplicate_dunder_all_entry import NoDuplicateDunderAllEntry
|
|
@@ -193,6 +194,7 @@ if TYPE_CHECKING:
|
|
|
193
194
|
|
|
194
195
|
REGISTRY: Mapping[str, type[Rule]] = MappingProxyType(
|
|
195
196
|
{
|
|
197
|
+
NoDatabaseProgrammability.id: NoDatabaseProgrammability,
|
|
196
198
|
RequireExplicitContractImplementation.id: RequireExplicitContractImplementation,
|
|
197
199
|
DiscourageNullableConstructorParameters.id: DiscourageNullableConstructorParameters,
|
|
198
200
|
RequirePublicDependencyContract.id: RequirePublicDependencyContract,
|
|
@@ -85,13 +85,27 @@ def _sql_noise_end(text: str, start: int, *, mask_dollar_quotes: bool) -> int |
|
|
|
85
85
|
end = text.find("\n", start)
|
|
86
86
|
return len(text) if end == -1 else end
|
|
87
87
|
if text.startswith("/*", start):
|
|
88
|
-
|
|
89
|
-
return len(text) if end == -1 else end + 2
|
|
88
|
+
return _block_comment_end(text, start)
|
|
90
89
|
if mask_dollar_quotes and ch == "$":
|
|
91
90
|
return _dollar_quote_end(text, start)
|
|
92
91
|
return None
|
|
93
92
|
|
|
94
93
|
|
|
94
|
+
def _block_comment_end(text: str, start: int) -> int:
|
|
95
|
+
depth = 1
|
|
96
|
+
i = start + 2
|
|
97
|
+
while i < len(text) and depth:
|
|
98
|
+
if text.startswith("/*", i):
|
|
99
|
+
depth += 1
|
|
100
|
+
i += 2
|
|
101
|
+
elif text.startswith("*/", i):
|
|
102
|
+
depth -= 1
|
|
103
|
+
i += 2
|
|
104
|
+
else:
|
|
105
|
+
i += 1
|
|
106
|
+
return i
|
|
107
|
+
|
|
108
|
+
|
|
95
109
|
def _dollar_quote_end(text: str, start: int) -> int | None:
|
|
96
110
|
delimiter_end = text.find("$", start + 1)
|
|
97
111
|
if delimiter_end == -1:
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
from pathlib import PurePosixPath
|
|
5
|
+
import re
|
|
6
|
+
from typing import TYPE_CHECKING, ClassVar, final, override
|
|
7
|
+
|
|
8
|
+
from sarj_python_lint.rule_base import (
|
|
9
|
+
AutofixPolicy,
|
|
10
|
+
Diagnostic,
|
|
11
|
+
ExampleFile,
|
|
12
|
+
ExampleOutcome,
|
|
13
|
+
Rule,
|
|
14
|
+
RuleCategory,
|
|
15
|
+
RuleDocumentation,
|
|
16
|
+
RuleExample,
|
|
17
|
+
Severity,
|
|
18
|
+
is_suppressed,
|
|
19
|
+
)
|
|
20
|
+
from sarj_python_lint.rules._sql import sql_string_value, strip_sql_noise
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from sarj_python_lint._file_context import PythonFileContext
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
_DATABASE_BEHAVIOR = re.compile(
|
|
28
|
+
r"(?:\A|;)\s*(?:CREATE\s+(?:OR\s+REPLACE\s+)?(?:FUNCTION|TRIGGER)|"
|
|
29
|
+
r"CREATE\s+CONSTRAINT\s+TRIGGER|ALTER\s+TABLE\s+[^;]+?\s+ENABLE\s+(?:(?:ALWAYS|REPLICA)\s+)?TRIGGER)\b",
|
|
30
|
+
re.IGNORECASE,
|
|
31
|
+
)
|
|
32
|
+
_BAD = 'await conn.execute("CREATE TRIGGER fail_counter BEFORE UPDATE ON batch EXECUTE FUNCTION fail_counter()")\n'
|
|
33
|
+
_GOOD = 'await conn.execute("ALTER TABLE batch ADD CONSTRAINT fail_counter CHECK (false) NOT VALID")\n'
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@final
|
|
37
|
+
class NoDatabaseProgrammability(Rule):
|
|
38
|
+
id = "no-database-programmability"
|
|
39
|
+
code = "SARJ470"
|
|
40
|
+
documentation: ClassVar[RuleDocumentation | None] = RuleDocumentation(
|
|
41
|
+
default_level=Severity.WARNING,
|
|
42
|
+
summary="Keep stored SQL functions and triggers out of embedded SQL.",
|
|
43
|
+
rationale="SQL hidden in Python can bypass migration-only architecture rules. Procedural fault fixtures require extra database objects and cleanup when a declarative constraint suffices.",
|
|
44
|
+
remediation="Use declarative constraints or explicit transactional application behavior, including in test fixtures. Use an exact SARJ470 suppression for an approved compatibility exception.",
|
|
45
|
+
category=RuleCategory.ARCHITECTURE,
|
|
46
|
+
autofix=AutofixPolicy.NONE,
|
|
47
|
+
limitations=(
|
|
48
|
+
"Checks inline execute/executemany SQL and import-proven psycopg.sql.SQL constructors, including aliases, concatenation, f-strings, and format calls. Test fixtures are included; generated Python is excluded.",
|
|
49
|
+
"Reports CREATE FUNCTION, CREATE OR REPLACE FUNCTION, CREATE TRIGGER, CREATE CONSTRAINT TRIGGER, and ALTER TABLE ENABLE TRIGGER. Existing function calls, DROP, and DISABLE remain valid.",
|
|
50
|
+
"SQL comments, quoted values, and dollar-quoted bodies are masked. Standalone example strings and Python functions are not SQL execution.",
|
|
51
|
+
"Runtime builders, SQL passed through named variables without SQL constructors, and dynamically generated DDL inside procedural bodies are not inferred. Non-PostgreSQL execution APIs are not distinguished.",
|
|
52
|
+
),
|
|
53
|
+
examples=(
|
|
54
|
+
RuleExample(
|
|
55
|
+
example_id="trigger-fault",
|
|
56
|
+
title="Procedural fault fixture",
|
|
57
|
+
outcome=ExampleOutcome.MATCH,
|
|
58
|
+
files=(ExampleFile.python("tests/fakes/batch_fault.py", _BAD),),
|
|
59
|
+
focus_path=PurePosixPath("tests/fakes/batch_fault.py"),
|
|
60
|
+
expected_count=1,
|
|
61
|
+
public=True,
|
|
62
|
+
),
|
|
63
|
+
RuleExample(
|
|
64
|
+
example_id="constraint-fault",
|
|
65
|
+
title="Declarative failure in a disposable database",
|
|
66
|
+
outcome=ExampleOutcome.NO_MATCH,
|
|
67
|
+
files=(ExampleFile.python("tests/fakes/batch_fault.py", _GOOD),),
|
|
68
|
+
focus_path=PurePosixPath("tests/fakes/batch_fault.py"),
|
|
69
|
+
expected_count=0,
|
|
70
|
+
public=True,
|
|
71
|
+
),
|
|
72
|
+
),
|
|
73
|
+
)
|
|
74
|
+
description = documentation.summary
|
|
75
|
+
|
|
76
|
+
@override
|
|
77
|
+
def check_context(self, context: PythonFileContext) -> list[Diagnostic]:
|
|
78
|
+
if context.generated or context.tree is None:
|
|
79
|
+
return []
|
|
80
|
+
diagnostics: list[Diagnostic] = []
|
|
81
|
+
for node in context.nodes(ast.Call):
|
|
82
|
+
query = _query_expression(node, context)
|
|
83
|
+
value = _literal_sql(query) if query is not None else None
|
|
84
|
+
if value is None or _DATABASE_BEHAVIOR.search(strip_sql_noise(value)) is None:
|
|
85
|
+
continue
|
|
86
|
+
if is_suppressed(context.source_lines, node.lineno, self.code):
|
|
87
|
+
continue
|
|
88
|
+
diagnostics.append(
|
|
89
|
+
Diagnostic(
|
|
90
|
+
path=context.path,
|
|
91
|
+
line=node.lineno,
|
|
92
|
+
col=node.col_offset + 1,
|
|
93
|
+
code=self.code,
|
|
94
|
+
severity=Severity.WARNING,
|
|
95
|
+
message="Stored SQL functions and triggers are prohibited by project architecture, including in test fixtures; use a declarative constraint or explicit transactional application code.",
|
|
96
|
+
)
|
|
97
|
+
)
|
|
98
|
+
return sorted(diagnostics, key=lambda item: (item.line, item.col))
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _query_expression(node: ast.Call, context: PythonFileContext) -> ast.expr | None:
|
|
102
|
+
if context.imports.resolves(node.func, sources=frozenset({"psycopg.sql"}), symbol="SQL") or (
|
|
103
|
+
isinstance(node.func, ast.Attribute)
|
|
104
|
+
and node.func.attr == "SQL"
|
|
105
|
+
and context.imports.resolves(node.func.value, sources=frozenset({"psycopg"}), symbol="sql")
|
|
106
|
+
):
|
|
107
|
+
return node.args[0] if node.args else None
|
|
108
|
+
if not isinstance(node.func, ast.Attribute) or node.func.attr not in {"execute", "executemany"}:
|
|
109
|
+
return None
|
|
110
|
+
if node.args:
|
|
111
|
+
return node.args[0]
|
|
112
|
+
return next((keyword.value for keyword in node.keywords if keyword.arg == "query"), None)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _literal_sql(node: ast.expr) -> str | None:
|
|
116
|
+
if isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute) and node.func.attr == "format":
|
|
117
|
+
return _literal_sql(node.func.value)
|
|
118
|
+
return sql_string_value(node)
|
|
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.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_ast_position.py
RENAMED
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_contract_annotation.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_dict_key_views.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_first_party.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_fixed_record.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_nominal_project.py
RENAMED
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_project_index.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_prose_budget.py
RENAMED
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_resource_provenance.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/_test_assertions.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.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
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/excessive_commentary.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/mock_without_spec.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_any_mapping_types.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_comment_cruft.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_delete_statement.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_dunder_all.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_fastapi_on_event.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
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_offset_pagination.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
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_restated_comment.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/no_secret_in_log.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.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.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/over_mocked_test.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/phase_label_comment.py
RENAMED
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.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
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/prefer_library_fake.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
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.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.9.0 → sarj_python_lint-1.9.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
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/redundant_docstring.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
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/typed_error_reasons.py
RENAMED
|
File without changes
|
|
File without changes
|
{sarj_python_lint-1.9.0 → sarj_python_lint-1.9.1}/src/sarj_python_lint/rules/unused_mock_setup.py
RENAMED
|
File without changes
|
|
File without changes
|