diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c817a69c01595..f50ca985e78ce 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -205,6 +205,14 @@ repos: files: ^airflow/models/taskinstance.py$|^airflow/models/taskinstancehistory.py$ pass_filenames: false require_serial: true + - id: prevent-usage-of-session.query + name: Prevent usage of session.query + entry: ./scripts/ci/pre_commit/usage_session_query.py + language: python + additional_dependencies: ['rich>=12.4.4'] + files: ^airflow.*\.py$|^task_sdk.*\.py + exclude: ^tests/.*\.py$|^task_sdk/tests/.*\.py$ + pass_filenames: true - id: check-deferrable-default name: Check and fix default value of default_deferrable language: python diff --git a/contributing-docs/08_static_code_checks.rst b/contributing-docs/08_static_code_checks.rst index 8eccb20a304ff..fd73efd6f86c1 100644 --- a/contributing-docs/08_static_code_checks.rst +++ b/contributing-docs/08_static_code_checks.rst @@ -336,6 +336,8 @@ require Breeze Docker image to be built locally. +-----------------------------------------------------------+--------------------------------------------------------+---------+ | pretty-format-json | Format JSON files | | +-----------------------------------------------------------+--------------------------------------------------------+---------+ +| prevent-usage-of-session.query | Prevent usage of session.query | | ++-----------------------------------------------------------+--------------------------------------------------------+---------+ | pylint | pylint | | +-----------------------------------------------------------+--------------------------------------------------------+---------+ | python-no-log-warn | Check if there are no deprecate log warn | | diff --git a/dev/breeze/doc/images/output_static-checks.svg b/dev/breeze/doc/images/output_static-checks.svg index ecdf3f100ca25..fbeaedcf36e09 100644 --- a/dev/breeze/doc/images/output_static-checks.svg +++ b/dev/breeze/doc/images/output_static-checks.svg @@ -364,48 +364,49 @@ fix-encoding-pragma | flynt | generate-airflow-diagrams | generate-openapi-spec | generate-pypi-readme | generate-tasksdk-datamodels | generate-volumes-for-sources | identity | insert-license | kubeconform | lint-chart-schema | lint-dockerfile | -lint-helm-chart | lint-json-schema | lint-markdown | mixed-line-ending |          -mypy-airflow | mypy-dev | mypy-docs | mypy-providers | mypy-task-sdk |            -pretty-format-json | pylint | python-no-log-warn | replace-bad-characters |       -rst-backticks | ruff | ruff-format | shellcheck | trailing-whitespace |           -ts-compile-format-lint-ui | update-black-version | update-breeze-cmd-output |     -update-breeze-readme-config-hash | update-chart-dependencies | update-er-diagram  -| update-extras | update-in-the-wild-to-be-sorted |                               -update-inlined-dockerfile-scripts | update-installed-providers-to-be-sorted |     -update-installers-and-pre-commit | update-local-yml-file |                        -update-migration-references | update-providers-build-files |                      -update-providers-dependencies | update-reproducible-source-date-epoch |           -update-spelling-wordlist-to-be-sorted | update-supported-versions |               -update-vendored-in-k8s-json-schema | update-version | validate-operators-init |   -yamllint | zizmor)                                                                ---show-diff-on-failure-sShow diff for files modified by the checks. ---initialize-environmentInitialize environment before running checks. ---max-initialization-attemptsMaximum number of attempts to initialize environment before giving up. -(INTEGER RANGE)                                                        -[default: 3; 1<=x<=10]                                                 -╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭─ Selecting files to run the checks on ───────────────────────────────────────────────────────────────────────────────╮ ---file-fList of files to run the checks on.(PATH) ---all-files-aRun checks on all files. ---commit-ref-rRun checks for this commit reference only (can be any git commit-ish reference). Mutually     -exclusive with --last-commit.                                                                 -(TEXT)                                                                                        ---last-commit-cRun checks for all files in last commit. Mutually exclusive with --commit-ref. ---only-my-changes-mRun checks for commits belonging to my PR only: for all commits between merge base to `main`  -branch and HEAD of your branch.                                                               -╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭─ Building image before running checks ───────────────────────────────────────────────────────────────────────────────╮ ---skip-image-upgrade-checkSkip checking if the CI image is up to date. ---force-buildForce image build no matter if it is determined as needed. ---github-repository-gGitHub repository used to pull, push run images.(TEXT)[default: apache/airflow] ---builderBuildx builder used to perform `docker buildx build` commands.(TEXT) -[default: autodetect]                                          -╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭─ Common options ─────────────────────────────────────────────────────────────────────────────────────────────────────╮ ---dry-run-DIf dry-run is set, commands are only printed, not executed. ---verbose-vPrint verbose information about performed steps. ---help-hShow this message and exit. -╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +lint-helm-chart | lint-json-schema | lint-markdown | lint-openapi |               +mixed-line-ending | mypy-airflow | mypy-dev | mypy-docs | mypy-providers |        +mypy-task-sdk | pretty-format-json | prevent-usage-of-session.query | pylint |    +python-no-log-warn | replace-bad-characters | rst-backticks | ruff | ruff-format  +| shellcheck | trailing-whitespace | ts-compile-format-lint-ui |                  +update-black-version | update-breeze-cmd-output |                                 +update-breeze-readme-config-hash | update-chart-dependencies | update-er-diagram  +| update-extras | update-in-the-wild-to-be-sorted |                               +update-inlined-dockerfile-scripts | update-installed-providers-to-be-sorted |     +update-installers-and-pre-commit | update-local-yml-file |                        +update-migration-references | update-openapi-spec-tags-to-be-sorted |             +update-providers-build-files | update-providers-dependencies |                    +update-reproducible-source-date-epoch | update-spelling-wordlist-to-be-sorted |   +update-supported-versions | update-vendored-in-k8s-json-schema | update-version | +validate-operators-init | yamllint | zizmor)                                      +--show-diff-on-failure-sShow diff for files modified by the checks. +--initialize-environmentInitialize environment before running checks. +--max-initialization-attemptsMaximum number of attempts to initialize environment before giving up. +(INTEGER RANGE)                                                        +[default: 3; 1<=x<=10]                                                 +╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +╭─ Selecting files to run the checks on ───────────────────────────────────────────────────────────────────────────────╮ +--file-fList of files to run the checks on.(PATH) +--all-files-aRun checks on all files. +--commit-ref-rRun checks for this commit reference only (can be any git commit-ish reference). Mutually     +exclusive with --last-commit.                                                                 +(TEXT)                                                                                        +--last-commit-cRun checks for all files in last commit. Mutually exclusive with --commit-ref. +--only-my-changes-mRun checks for commits belonging to my PR only: for all commits between merge base to `main`  +branch and HEAD of your branch.                                                               +╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +╭─ Building image before running checks ───────────────────────────────────────────────────────────────────────────────╮ +--skip-image-upgrade-checkSkip checking if the CI image is up to date. +--force-buildForce image build no matter if it is determined as needed. +--github-repository-gGitHub repository used to pull, push run images.(TEXT)[default: apache/airflow] +--builderBuildx builder used to perform `docker buildx build` commands.(TEXT) +[default: autodetect]                                          +╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +╭─ Common options ─────────────────────────────────────────────────────────────────────────────────────────────────────╮ +--dry-run-DIf dry-run is set, commands are only printed, not executed. +--verbose-vPrint verbose information about performed steps. +--help-hShow this message and exit. +╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/dev/breeze/doc/images/output_static-checks.txt b/dev/breeze/doc/images/output_static-checks.txt index b92b4de9e174c..7be097817adde 100644 --- a/dev/breeze/doc/images/output_static-checks.txt +++ b/dev/breeze/doc/images/output_static-checks.txt @@ -1 +1 @@ -8e8c3bb6193f3dbad7af5cae63d28145 +d1ee6181aeefcf228e9f2f37055a98d9 diff --git a/dev/breeze/src/airflow_breeze/pre_commit_ids.py b/dev/breeze/src/airflow_breeze/pre_commit_ids.py index a303d9dd262e6..6ae9fd5ec0e3a 100644 --- a/dev/breeze/src/airflow_breeze/pre_commit_ids.py +++ b/dev/breeze/src/airflow_breeze/pre_commit_ids.py @@ -123,6 +123,7 @@ "mypy-providers", "mypy-task-sdk", "pretty-format-json", + "prevent-usage-of-session.query", "pylint", "python-no-log-warn", "replace-bad-characters", diff --git a/scripts/ci/pre_commit/usage_session_query.py b/scripts/ci/pre_commit/usage_session_query.py new file mode 100755 index 0000000000000..cf8cd10957eab --- /dev/null +++ b/scripts/ci/pre_commit/usage_session_query.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +import ast +import sys +from pathlib import Path + +from rich.console import Console + +console = Console(color_system="standard", width=200) + + +def check_session_query(mod: ast.Module) -> int: + errors = 0 + for node in ast.walk(mod): + if isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute): + if ( + node.func.attr == "query" + and isinstance(node.func.value, ast.Name) + and node.func.value.id == "session" + ): + console.print( + f"\nUse of legacy `session.query` detected on line {node.lineno}. " + f"\nSQLAlchemy 2.0 deprecates the `Query` object" + f"use the `select()` construct instead." + ) + errors += 1 + return errors + + +def main(): + for file in sys.argv[1:]: + file_path = Path(file) + ast_module = ast.parse(file_path.read_text(encoding="utf-8"), file) + errors = check_session_query(ast_module) + return 1 if errors > 0 else 0 + + +if __name__ == "__main__": + sys.exit(main())