sarj-python-lint 0.76.0__tar.gz → 0.77.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/PKG-INFO +1 -1
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/pyproject.toml +1 -1
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_registry.py +2 -0
- sarj_python_lint-0.77.0/src/sarj_python_lint/rules/no_fastapi_on_event.py +168 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/.gitignore +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/LICENSE +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/README.md +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/__init__.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/__main__.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/_filesystem.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/_ratchet_cli.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/_secret_names.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/_version.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/py.typed +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/ratchet.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rule_base.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/__init__.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_ast_index.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_comments.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_docstrings.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_fastapi.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_first_party.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_imports.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_logging.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_paths.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_project_index.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_prose_budget.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_pytest.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_sql.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_suppression_comments.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_test_assertions.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/created_at_order_requires_tiebreaker.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/defect_xfail_requires_strict.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/docstring_args_restate_signature.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/docstring_returns_restate_signature.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/duplicate_test_body.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/duplicated_override_docstring.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/fastapi_openapi_contract.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/fixture_returns_bare_tuple.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/get_delegates_to_get_many.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/iac_source_coupled_test.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/invalid_pydantic_field_default.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/kwarg_heavy_construction_in_test.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/mock_without_spec.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/negative_only_http_status_assertion.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_aggregation_in_store_query.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_comment_cruft.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_conftest_test_module_import.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_cors_wildcard_with_credentials.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_duplicate_dunder_all_entry.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_file_level_escape_hatch_noqa.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_first_party_private_import.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_frozen_after_validator_field_write.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_gen_random_uuid_in_sql.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_generic_single_export_module.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_hidden_constructor_fallback.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_isinstance_union_chain.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_long_comment.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_nested_pydantic_field_validator.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_offset_pagination.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_optional_tenant_predicate.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_query_with_many_joins.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_redundant_literal_description.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_repeated_string_literal.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_restated_comment.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_secret_in_log.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_select_star.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_sentinel_return_on_except.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_stdlib_logging.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_string_concat_in_loop.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_tautological_expect.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_typed_doc_sections.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_unique_violation_message_match.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_unnecessary_docstring.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_vague_suppression_description.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/opaque_parametrize_case_needs_id.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/over_mocked_test.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/phase_label_comment.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_class_row.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_constant_time_secret_compare.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_fstring_over_concat.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_immutable_module_constant.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_library_fake.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_match_assert_never.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_match_type_dispatch.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_module_level_constant.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_namedtuple_over_tuple_return.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_nominal_id_types.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_non_nullable_collection.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_one_for_required_row.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_or_pattern.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_self_documenting_constant.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_self_type_annotation.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_str_enum.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_struct_over_namedtuple.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_timedelta_for_durations.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_walrus_comprehension_filter.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_walrus_regex_match.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_walrus_stream_loop.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/preserve_declared_nominal_id.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/preserve_enum_types.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/production_derived_test_cases.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/pydantic_at_boundaries.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/redundant_class_docstring.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/redundant_docstring.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/redundant_module_docstring.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/repeated_static_call_cases.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/require_keyword_only_swap_prone_params.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/require_nodecode_for_splitting_settings_field.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/require_port_for_service.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/require_pydantic_for_external_json.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/require_pydantic_ordinal_lower_bound.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/require_validated_row_factory.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/restated_test_docstring.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/source_coupled_test.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/sql_requires_injected_pool_owner.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/stepdown.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/store_insert_requires_on_conflict.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/trailing_value_narration.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/trivially_true_assertion.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/uncontrolled_randomness_in_test.py +0 -0
- {sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/unused_mock_setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: sarj-python-lint
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.77.0
|
|
4
4
|
Summary: Custom Python lint rules — AST-based, pre-commit-friendly, hypermodern defaults
|
|
5
5
|
Project-URL: Homepage, https://code-standards.sarj.ai/rules/python/
|
|
6
6
|
Project-URL: Documentation, https://code-standards.sarj.ai/rules/python/
|
|
@@ -38,6 +38,7 @@ from sarj_python_lint.rules.no_cors_wildcard_with_credentials import (
|
|
|
38
38
|
NoCorsWildcardWithCredentials,
|
|
39
39
|
)
|
|
40
40
|
from sarj_python_lint.rules.no_duplicate_dunder_all_entry import NoDuplicateDunderAllEntry
|
|
41
|
+
from sarj_python_lint.rules.no_fastapi_on_event import NoFastapiOnEvent
|
|
41
42
|
from sarj_python_lint.rules.no_file_level_escape_hatch_noqa import NoFileLevelEscapeHatchNoqa
|
|
42
43
|
from sarj_python_lint.rules.no_first_party_private_import import (
|
|
43
44
|
NoFirstPartyPrivateImport,
|
|
@@ -205,6 +206,7 @@ REGISTRY: Mapping[str, type[Rule]] = MappingProxyType(
|
|
|
205
206
|
NoGenRandomUuidInSql.id: NoGenRandomUuidInSql,
|
|
206
207
|
NoHiddenConstructorFallback.id: NoHiddenConstructorFallback,
|
|
207
208
|
NoFileLevelEscapeHatchNoqa.id: NoFileLevelEscapeHatchNoqa,
|
|
209
|
+
NoFastapiOnEvent.id: NoFastapiOnEvent,
|
|
208
210
|
NoOptionalTenantPredicate.id: NoOptionalTenantPredicate,
|
|
209
211
|
NoTautologicalExpect.id: NoTautologicalExpect,
|
|
210
212
|
PreferLibraryFake.id: PreferLibraryFake,
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
from pathlib import PurePosixPath
|
|
5
|
+
from typing import TYPE_CHECKING, final, override
|
|
6
|
+
|
|
7
|
+
from sarj_python_lint.rule_base import (
|
|
8
|
+
AutofixPolicy,
|
|
9
|
+
Diagnostic,
|
|
10
|
+
ExampleFile,
|
|
11
|
+
ExampleOutcome,
|
|
12
|
+
Rule,
|
|
13
|
+
RuleCategory,
|
|
14
|
+
RuleDocumentation,
|
|
15
|
+
RuleExample,
|
|
16
|
+
parse_or_none,
|
|
17
|
+
)
|
|
18
|
+
from sarj_python_lint.rules._imports import ImportIndex
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
_APP_TYPES = frozenset({("fastapi", "FastAPI"), ("starlette.applications", "Starlette")})
|
|
26
|
+
_EVENT_NAMES = frozenset({"startup", "shutdown"})
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@final
|
|
30
|
+
class NoFastapiOnEvent(Rule):
|
|
31
|
+
id = "no-fastapi-on-event"
|
|
32
|
+
code = "SARJ427"
|
|
33
|
+
documentation = RuleDocumentation(
|
|
34
|
+
summary="Deprecated FastAPI or Starlette on_event lifecycle registration.",
|
|
35
|
+
rationale=(
|
|
36
|
+
"The on_event API is deprecated and splits related startup and shutdown state across callbacks; lifespan "
|
|
37
|
+
"keeps acquisition and cleanup in one async context manager and is the supported lifecycle contract."
|
|
38
|
+
),
|
|
39
|
+
remediation="Define an async lifespan context manager and pass it as FastAPI(lifespan=...) or Starlette(lifespan=...).",
|
|
40
|
+
category=RuleCategory.CORRECTNESS,
|
|
41
|
+
autofix=AutofixPolicy.NONE,
|
|
42
|
+
limitations=(
|
|
43
|
+
"Only decorators on a directly constructed FastAPI/Starlette application or a parameter annotated with one are checked.",
|
|
44
|
+
"Factory-returned applications and dynamically selected event names are intentionally not inferred.",
|
|
45
|
+
),
|
|
46
|
+
examples=(
|
|
47
|
+
RuleExample(
|
|
48
|
+
example_id="deprecated-startup-event",
|
|
49
|
+
title="Do not register startup through on_event",
|
|
50
|
+
outcome=ExampleOutcome.MATCH,
|
|
51
|
+
files=(
|
|
52
|
+
ExampleFile.python(
|
|
53
|
+
"app/main.py",
|
|
54
|
+
'from fastapi import FastAPI\napp = FastAPI()\n\n@app.on_event("startup")\nasync def start() -> None:\n pass\n',
|
|
55
|
+
),
|
|
56
|
+
),
|
|
57
|
+
focus_path=PurePosixPath("app/main.py"),
|
|
58
|
+
expected_count=1,
|
|
59
|
+
public=True,
|
|
60
|
+
),
|
|
61
|
+
RuleExample(
|
|
62
|
+
example_id="lifespan-context-manager",
|
|
63
|
+
title="Pair startup and shutdown in lifespan",
|
|
64
|
+
outcome=ExampleOutcome.NO_MATCH,
|
|
65
|
+
files=(
|
|
66
|
+
ExampleFile.python(
|
|
67
|
+
"app/main.py",
|
|
68
|
+
"from contextlib import asynccontextmanager\nfrom fastapi import FastAPI\n\n"
|
|
69
|
+
"@asynccontextmanager\nasync def lifespan(app: FastAPI):\n yield\n\napp = FastAPI(lifespan=lifespan)\n",
|
|
70
|
+
),
|
|
71
|
+
),
|
|
72
|
+
focus_path=PurePosixPath("app/main.py"),
|
|
73
|
+
expected_count=0,
|
|
74
|
+
public=True,
|
|
75
|
+
),
|
|
76
|
+
),
|
|
77
|
+
)
|
|
78
|
+
description = documentation.summary
|
|
79
|
+
|
|
80
|
+
@override
|
|
81
|
+
def check(self, path: Path, source: str) -> list[Diagnostic]:
|
|
82
|
+
tree = parse_or_none(path, source)
|
|
83
|
+
if tree is None:
|
|
84
|
+
return []
|
|
85
|
+
imports = ImportIndex.from_tree(tree)
|
|
86
|
+
return _scope_diagnostics(path, tree.body, imports)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _scope_diagnostics(
|
|
90
|
+
path: Path,
|
|
91
|
+
statements: list[ast.stmt],
|
|
92
|
+
imports: ImportIndex,
|
|
93
|
+
*,
|
|
94
|
+
extra_app_names: frozenset[str] = frozenset(),
|
|
95
|
+
) -> list[Diagnostic]:
|
|
96
|
+
app_names = _assigned_app_names(statements, imports) | extra_app_names
|
|
97
|
+
findings: list[Diagnostic] = []
|
|
98
|
+
for statement in statements:
|
|
99
|
+
if not isinstance(statement, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
100
|
+
continue
|
|
101
|
+
findings.extend(
|
|
102
|
+
Diagnostic(
|
|
103
|
+
path=path,
|
|
104
|
+
line=decorator.lineno,
|
|
105
|
+
col=decorator.col_offset + 1,
|
|
106
|
+
code="SARJ427",
|
|
107
|
+
message=(
|
|
108
|
+
"FastAPI/Starlette on_event is deprecated. Put startup and shutdown work in an async lifespan "
|
|
109
|
+
"context manager and pass it to the application constructor."
|
|
110
|
+
),
|
|
111
|
+
)
|
|
112
|
+
for decorator in statement.decorator_list
|
|
113
|
+
if _is_on_event_decorator(decorator, app_names)
|
|
114
|
+
)
|
|
115
|
+
findings.extend(
|
|
116
|
+
_scope_diagnostics(
|
|
117
|
+
path,
|
|
118
|
+
statement.body,
|
|
119
|
+
imports,
|
|
120
|
+
extra_app_names=_annotated_app_parameters(statement.args, imports),
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
return findings
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _assigned_app_names(statements: list[ast.stmt], imports: ImportIndex) -> frozenset[str]:
|
|
127
|
+
names: set[str] = set()
|
|
128
|
+
for statement in statements:
|
|
129
|
+
if not isinstance(statement, (ast.Assign, ast.AnnAssign)):
|
|
130
|
+
continue
|
|
131
|
+
value = statement.value
|
|
132
|
+
if not isinstance(value, ast.Call) or not any(
|
|
133
|
+
imports.resolves(value.func, sources=frozenset({source}), symbol=symbol) for source, symbol in _APP_TYPES
|
|
134
|
+
):
|
|
135
|
+
continue
|
|
136
|
+
targets = statement.targets if isinstance(statement, ast.Assign) else [statement.target]
|
|
137
|
+
names.update(target.id for target in targets if isinstance(target, ast.Name))
|
|
138
|
+
return frozenset(names)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _annotated_app_parameters(arguments: ast.arguments, imports: ImportIndex) -> frozenset[str]:
|
|
142
|
+
parameters = [*arguments.posonlyargs, *arguments.args, *arguments.kwonlyargs]
|
|
143
|
+
if arguments.vararg is not None:
|
|
144
|
+
parameters.append(arguments.vararg)
|
|
145
|
+
if arguments.kwarg is not None:
|
|
146
|
+
parameters.append(arguments.kwarg)
|
|
147
|
+
return frozenset(
|
|
148
|
+
parameter.arg
|
|
149
|
+
for parameter in parameters
|
|
150
|
+
if parameter.annotation is not None
|
|
151
|
+
and any(
|
|
152
|
+
imports.resolves(parameter.annotation, sources=frozenset({source}), symbol=symbol)
|
|
153
|
+
for source, symbol in _APP_TYPES
|
|
154
|
+
)
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _is_on_event_decorator(node: ast.expr, app_names: frozenset[str]) -> bool:
|
|
159
|
+
return (
|
|
160
|
+
isinstance(node, ast.Call)
|
|
161
|
+
and isinstance(node.func, ast.Attribute)
|
|
162
|
+
and node.func.attr == "on_event"
|
|
163
|
+
and isinstance(node.func.value, ast.Name)
|
|
164
|
+
and node.func.value.id in app_names
|
|
165
|
+
and len(node.args) == 1
|
|
166
|
+
and isinstance(node.args[0], ast.Constant)
|
|
167
|
+
and node.args[0].value in _EVENT_NAMES
|
|
168
|
+
)
|
|
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-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_ast_index.py
RENAMED
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_docstrings.py
RENAMED
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_first_party.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_project_index.py
RENAMED
|
File without changes
|
{sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_prose_budget.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/_test_assertions.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-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/mock_without_spec.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_long_comment.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-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_secret_in_log.py
RENAMED
|
File without changes
|
{sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_select_star.py
RENAMED
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/no_stdlib_logging.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-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/over_mocked_test.py
RENAMED
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/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
|
{sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/prefer_or_pattern.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/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
|
{sarj_python_lint-0.76.0 → sarj_python_lint-0.77.0}/src/sarj_python_lint/rules/unused_mock_setup.py
RENAMED
|
File without changes
|