diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index ce71a748dcd81..0c73d57904f02 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -908,6 +908,12 @@ repos:
entry: ./scripts/ci/pre_commit/pre_commit_www_lint.py
additional_dependencies: ['yarn@1.22.19']
pass_filenames: false
+ - id: check-tests-unittest-testcase
+ name: Check that unit tests do not inherit from unittest.TestCase
+ entry: ./scripts/ci/pre_commit/pre_commit_unittest_testcase.py
+ language: python
+ pass_filenames: true
+ files: ^tests/.*\.py$
## ADD MOST PRE-COMMITS ABOVE THAT LINE
# The below pre-commits are those requiring CI image to be built
- id: mypy-dev
diff --git a/STATIC_CODE_CHECKS.rst b/STATIC_CODE_CHECKS.rst
index 18c6b0aeb9ec9..caddd825e5fbf 100644
--- a/STATIC_CODE_CHECKS.rst
+++ b/STATIC_CODE_CHECKS.rst
@@ -227,6 +227,8 @@ require Breeze Docker image to be build locally.
+-----------------------------------------------------------+------------------------------------------------------------------+---------+
| check-system-tests-tocs | Check that system tests is properly added | |
+-----------------------------------------------------------+------------------------------------------------------------------+---------+
+| check-tests-unittest-testcase | Check that unit tests do not inherit from unittest.TestCase | |
++-----------------------------------------------------------+------------------------------------------------------------------+---------+
| check-urlparse-usage-in-code | Don't use urlparse in code | |
+-----------------------------------------------------------+------------------------------------------------------------------+---------+
| check-xml | Check XML files with xmllint | |
diff --git a/dev/breeze/src/airflow_breeze/pre_commit_ids.py b/dev/breeze/src/airflow_breeze/pre_commit_ids.py
index 236525e31481f..ce33a62ed739f 100644
--- a/dev/breeze/src/airflow_breeze/pre_commit_ids.py
+++ b/dev/breeze/src/airflow_breeze/pre_commit_ids.py
@@ -67,6 +67,7 @@
"check-start-date-not-used-in-defaults",
"check-system-tests-present",
"check-system-tests-tocs",
+ "check-tests-unittest-testcase",
"check-urlparse-usage-in-code",
"check-xml",
"codespell",
diff --git a/images/breeze/output-commands-hash.txt b/images/breeze/output-commands-hash.txt
index ea49811b11b21..44538a16b61b4 100644
--- a/images/breeze/output-commands-hash.txt
+++ b/images/breeze/output-commands-hash.txt
@@ -55,7 +55,7 @@ setup:version:123b462a421884dc2320ffc5e54b2478
setup:26f37743534e14f5aad5300aad920301
shell:bd3e004a92ebcec8feb40fc5cd95872d
start-airflow:ee5066f1420a489864b48bc4e5e472da
-static-checks:543f0c776d0f198e80a0f75058445bb2
+static-checks:806eafbc99a76ebba6178b0b461b3499
stop:e5aa686b4e53707ced4039d8414d5cd6
testing:docker-compose-tests:b86c044b24138af0659a05ed6331576c
testing:helm-tests:936cf28fd84ce4ff5113795fdae9624b
diff --git a/images/breeze/output_setup.svg b/images/breeze/output_setup.svg
index c313db50bab0c..65185a603f97a 100644
--- a/images/breeze/output_setup.svg
+++ b/images/breeze/output_setup.svg
@@ -35,8 +35,8 @@
.breeze-setup-r1 { fill: #c5c8c6;font-weight: bold }
.breeze-setup-r2 { fill: #c5c8c6 }
.breeze-setup-r3 { fill: #d0b344;font-weight: bold }
-.breeze-setup-r4 { fill: #68a0b3;font-weight: bold }
-.breeze-setup-r5 { fill: #868887 }
+.breeze-setup-r4 { fill: #868887 }
+.breeze-setup-r5 { fill: #68a0b3;font-weight: bold }
.breeze-setup-r6 { fill: #98a84b;font-weight: bold }
@@ -102,21 +102,21 @@
-Usage: breeze setup [OPTIONS] COMMAND [ARGS]...
+Usage: breeze setup [OPTIONS] COMMAND [ARGS]...
Tools that developers can use to configure Breeze
-╭─ Common options ─────────────────────────────────────────────────────────────────────────────────────────────────────╮
-│--help-hShow this message and exit.│
-╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
-╭─ Commands ───────────────────────────────────────────────────────────────────────────────────────────────────────────╮
-│autocomplete Enables autocompletion of breeze commands. │
-│check-all-params-in-groups Check that all parameters are put in groups. │
-│config Show/update configuration (Python, Backend, Cheatsheet, ASCIIART). │
-│regenerate-command-images Regenerate breeze command images. │
-│self-upgrade Self upgrade Breeze. │
-│version Print information about version of apache-airflow-breeze. │
-╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─ Common options ─────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│--help-hShow this message and exit.│
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─ Commands ───────────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│autocomplete Enables autocompletion of breeze commands. │
+│check-all-params-in-groups Check that all parameters are put in groups. │
+│config Show/update configuration (Python, Backend, Cheatsheet, ASCIIART). │
+│regenerate-command-images Regenerate breeze command images. │
+│self-upgrade Self upgrade Breeze. │
+│version Print information about version of apache-airflow-breeze. │
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
diff --git a/images/breeze/output_setup_check-all-params-in-groups.svg b/images/breeze/output_setup_check-all-params-in-groups.svg
index 096285f97fb7c..1ed51d446efa8 100644
--- a/images/breeze/output_setup_check-all-params-in-groups.svg
+++ b/images/breeze/output_setup_check-all-params-in-groups.svg
@@ -35,8 +35,8 @@
.breeze-setup-check-all-params-in-groups-r1 { fill: #c5c8c6;font-weight: bold }
.breeze-setup-check-all-params-in-groups-r2 { fill: #c5c8c6 }
.breeze-setup-check-all-params-in-groups-r3 { fill: #d0b344;font-weight: bold }
-.breeze-setup-check-all-params-in-groups-r4 { fill: #68a0b3;font-weight: bold }
-.breeze-setup-check-all-params-in-groups-r5 { fill: #868887 }
+.breeze-setup-check-all-params-in-groups-r4 { fill: #868887 }
+.breeze-setup-check-all-params-in-groups-r5 { fill: #68a0b3;font-weight: bold }
.breeze-setup-check-all-params-in-groups-r6 { fill: #8d7b39 }
.breeze-setup-check-all-params-in-groups-r7 { fill: #98a84b;font-weight: bold }
@@ -139,33 +139,33 @@
-Usage: breeze setup check-all-params-in-groups [OPTIONS]
+Usage: breeze setup check-all-params-in-groups [OPTIONS]
Check that all parameters are put in groups.
-╭─ Check all params in groups flags ───────────────────────────────────────────────────────────────────────────────────╮
-│--commandCommand(s) to regenerate images for (optional, might be repeated) │
-│(main | build-docs | ci:fix-ownership | ci:free-space | ci:get-workflow-info | ci:resource-check | │
-│ci:selective-check | ci | ci-image:build | ci-image:pull | ci-image:verify | ci-image | cleanup | │
-│compile-www-assets | exec | k8s:build-k8s-image | k8s:configure-cluster | k8s:create-cluster | │
-│k8s:delete-cluster | k8s:deploy-airflow | k8s:k9s | k8s:logs | k8s:run-complete-tests | k8s:setup-env |│
-│k8s:shell | k8s:status | k8s:tests | k8s:upload-k8s-image | k8s | prod-image:build | prod-image:pull | │
-│prod-image:verify | prod-image | release-management:create-minor-branch | │
-│release-management:generate-constraints | release-management:generate-issue-content-providers | │
-│release-management:install-provider-packages | release-management:prepare-airflow-package | │
-│release-management:prepare-provider-documentation | release-management:prepare-provider-packages | │
-│release-management:release-prod-images | release-management:start-rc-process | │
-│release-management:start-release | release-management:verify-provider-packages | release-management | │
-│setup:autocomplete | setup:check-all-params-in-groups | setup:config | setup:regenerate-command-images │
-│| setup:self-upgrade | setup:version | setup | shell | start-airflow | static-checks | stop | │
-│testing:docker-compose-tests | testing:helm-tests | testing:integration-tests | testing:tests | │
-│testing) │
-╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
-╭─ Common options ─────────────────────────────────────────────────────────────────────────────────────────────────────╮
-│--verbose-vPrint verbose information about performed steps.│
-│--dry-run-DIf dry-run is set, commands are only printed, not executed.│
-│--help-hShow this message and exit.│
-╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─ Check all params in groups flags ───────────────────────────────────────────────────────────────────────────────────╮
+│--commandCommand(s) to regenerate images for (optional, might be repeated) │
+│(main | build-docs | ci:fix-ownership | ci:free-space | ci:get-workflow-info | ci:resource-check | │
+│ci:selective-check | ci | ci-image:build | ci-image:pull | ci-image:verify | ci-image | cleanup | │
+│compile-www-assets | exec | k8s:build-k8s-image | k8s:configure-cluster | k8s:create-cluster | │
+│k8s:delete-cluster | k8s:deploy-airflow | k8s:k9s | k8s:logs | k8s:run-complete-tests | k8s:setup-env |│
+│k8s:shell | k8s:status | k8s:tests | k8s:upload-k8s-image | k8s | prod-image:build | prod-image:pull | │
+│prod-image:verify | prod-image | release-management:create-minor-branch | │
+│release-management:generate-constraints | release-management:generate-issue-content-providers | │
+│release-management:install-provider-packages | release-management:prepare-airflow-package | │
+│release-management:prepare-provider-documentation | release-management:prepare-provider-packages | │
+│release-management:release-prod-images | release-management:start-rc-process | │
+│release-management:start-release | release-management:verify-provider-packages | release-management | │
+│setup:autocomplete | setup:check-all-params-in-groups | setup:config | setup:regenerate-command-images │
+│| setup:self-upgrade | setup:version | setup | shell | start-airflow | static-checks | stop | │
+│testing:docker-compose-tests | testing:helm-tests | testing:integration-tests | testing:tests | │
+│testing) │
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─ Common options ─────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│--verbose-vPrint verbose information about performed steps.│
+│--dry-run-DIf dry-run is set, commands are only printed, not executed.│
+│--help-hShow this message and exit.│
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
diff --git a/images/breeze/output_setup_regenerate-command-images.svg b/images/breeze/output_setup_regenerate-command-images.svg
index b8bcafe739900..5bb38f1c124b7 100644
--- a/images/breeze/output_setup_regenerate-command-images.svg
+++ b/images/breeze/output_setup_regenerate-command-images.svg
@@ -35,8 +35,8 @@
.breeze-setup-regenerate-command-images-r1 { fill: #c5c8c6;font-weight: bold }
.breeze-setup-regenerate-command-images-r2 { fill: #c5c8c6 }
.breeze-setup-regenerate-command-images-r3 { fill: #d0b344;font-weight: bold }
-.breeze-setup-regenerate-command-images-r4 { fill: #68a0b3;font-weight: bold }
-.breeze-setup-regenerate-command-images-r5 { fill: #868887 }
+.breeze-setup-regenerate-command-images-r4 { fill: #868887 }
+.breeze-setup-regenerate-command-images-r5 { fill: #68a0b3;font-weight: bold }
.breeze-setup-regenerate-command-images-r6 { fill: #8d7b39 }
.breeze-setup-regenerate-command-images-r7 { fill: #98a84b;font-weight: bold }
@@ -148,36 +148,36 @@
-Usage: breeze setup regenerate-command-images [OPTIONS]
+Usage: breeze setup regenerate-command-images [OPTIONS]
Regenerate breeze command images.
-╭─ Image regeneration option ──────────────────────────────────────────────────────────────────────────────────────────╮
-│--forceForces regeneration of all images│
-│--commandCommand(s) to regenerate images for (optional, might be repeated) │
-│(main | build-docs | ci:fix-ownership | ci:free-space | ci:get-workflow-info | ci:resource-check | │
-│ci:selective-check | ci | ci-image:build | ci-image:pull | ci-image:verify | ci-image | cleanup | │
-│compile-www-assets | exec | k8s:build-k8s-image | k8s:configure-cluster | k8s:create-cluster | │
-│k8s:delete-cluster | k8s:deploy-airflow | k8s:k9s | k8s:logs | k8s:run-complete-tests | │
-│k8s:setup-env | k8s:shell | k8s:status | k8s:tests | k8s:upload-k8s-image | k8s | prod-image:build |│
-│prod-image:pull | prod-image:verify | prod-image | release-management:create-minor-branch | │
-│release-management:generate-constraints | release-management:generate-issue-content-providers | │
-│release-management:install-provider-packages | release-management:prepare-airflow-package | │
-│release-management:prepare-provider-documentation | release-management:prepare-provider-packages | │
-│release-management:release-prod-images | release-management:start-rc-process | │
-│release-management:start-release | release-management:verify-provider-packages | release-management │
-│| setup:autocomplete | setup:check-all-params-in-groups | setup:config | │
-│setup:regenerate-command-images | setup:self-upgrade | setup:version | setup | shell | start-airflow│
-│| static-checks | stop | testing:docker-compose-tests | testing:helm-tests | │
-│testing:integration-tests | testing:tests | testing) │
-│--check-onlyOnly check if some images need to be regenerated. Return 0 if no need or 1 if needed. Cannot be used│
-│together with --command flag or --force. │
-╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
-╭─ Common options ─────────────────────────────────────────────────────────────────────────────────────────────────────╮
-│--verbose-vPrint verbose information about performed steps.│
-│--dry-run-DIf dry-run is set, commands are only printed, not executed.│
-│--help-hShow this message and exit.│
-╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─ Image regeneration option ──────────────────────────────────────────────────────────────────────────────────────────╮
+│--forceForces regeneration of all images│
+│--commandCommand(s) to regenerate images for (optional, might be repeated) │
+│(main | build-docs | ci:fix-ownership | ci:free-space | ci:get-workflow-info | ci:resource-check | │
+│ci:selective-check | ci | ci-image:build | ci-image:pull | ci-image:verify | ci-image | cleanup | │
+│compile-www-assets | exec | k8s:build-k8s-image | k8s:configure-cluster | k8s:create-cluster | │
+│k8s:delete-cluster | k8s:deploy-airflow | k8s:k9s | k8s:logs | k8s:run-complete-tests | │
+│k8s:setup-env | k8s:shell | k8s:status | k8s:tests | k8s:upload-k8s-image | k8s | prod-image:build |│
+│prod-image:pull | prod-image:verify | prod-image | release-management:create-minor-branch | │
+│release-management:generate-constraints | release-management:generate-issue-content-providers | │
+│release-management:install-provider-packages | release-management:prepare-airflow-package | │
+│release-management:prepare-provider-documentation | release-management:prepare-provider-packages | │
+│release-management:release-prod-images | release-management:start-rc-process | │
+│release-management:start-release | release-management:verify-provider-packages | release-management │
+│| setup:autocomplete | setup:check-all-params-in-groups | setup:config | │
+│setup:regenerate-command-images | setup:self-upgrade | setup:version | setup | shell | start-airflow│
+│| static-checks | stop | testing:docker-compose-tests | testing:helm-tests | │
+│testing:integration-tests | testing:tests | testing) │
+│--check-onlyOnly check if some images need to be regenerated. Return 0 if no need or 1 if needed. Cannot be used│
+│together with --command flag or --force. │
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─ Common options ─────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│--verbose-vPrint verbose information about performed steps.│
+│--dry-run-DIf dry-run is set, commands are only printed, not executed.│
+│--help-hShow this message and exit.│
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
diff --git a/images/breeze/output_static-checks.svg b/images/breeze/output_static-checks.svg
index 04b6730555456..f9dd25c95aa60 100644
--- a/images/breeze/output_static-checks.svg
+++ b/images/breeze/output_static-checks.svg
@@ -35,8 +35,8 @@
.breeze-static-checks-r1 { fill: #c5c8c6;font-weight: bold }
.breeze-static-checks-r2 { fill: #c5c8c6 }
.breeze-static-checks-r3 { fill: #d0b344;font-weight: bold }
-.breeze-static-checks-r4 { fill: #68a0b3;font-weight: bold }
-.breeze-static-checks-r5 { fill: #868887 }
+.breeze-static-checks-r4 { fill: #868887 }
+.breeze-static-checks-r5 { fill: #68a0b3;font-weight: bold }
.breeze-static-checks-r6 { fill: #98a84b;font-weight: bold }
.breeze-static-checks-r7 { fill: #8d7b39 }
@@ -223,61 +223,61 @@
-Usage: breeze static-checks [OPTIONS] [PRECOMMIT_ARGS]...
+Usage: breeze static-checks [OPTIONS] [PRECOMMIT_ARGS]...
Run static checks.
-╭─ Pre-commit flags ───────────────────────────────────────────────────────────────────────────────────────────────────╮
-│--type-tType(s) of the static checks to run. │
-│(all | black | blacken-docs | check-airflow-config-yaml-consistent | │
-│check-airflow-provider-compatibility | check-apache-license-rat | │
-│check-base-operator-partial-arguments | check-base-operator-usage | │
-│check-boring-cyborg-configuration | check-breeze-top-dependencies-limited | │
-│check-builtin-literals | check-changelog-has-no-duplicates | │
-│check-core-deprecation-classes | check-daysago-import-from-utils | │
-│check-decorated-operator-implements-custom-name | check-docstring-param-types | │
-│check-example-dags-urls | check-executables-have-shebangs | │
-│check-extra-packages-references | check-extras-order | check-for-inclusive-language | │
-│check-hooks-apply | check-incorrect-use-of-LoggingMixin | check-init-decorator-arguments│
-│| check-lazy-logging | check-links-to-example-dags-do-not-use-hardcoded-versions | │
-│check-merge-conflict | check-newsfragments-are-valid | │
-│check-no-providers-in-core-examples | check-no-relative-imports | │
-│check-only-new-session-with-provide-session | │
-│check-persist-credentials-disabled-in-github-workflows | │
-│check-pre-commit-information-consistent | check-provide-create-sessions-imports | │
-│check-provider-yaml-valid | check-providers-init-file-missing | │
-│check-providers-subpackages-init-file-exist | check-pydevd-left-in-code | │
-│check-revision-heads-map | check-safe-filter-usage-in-html | check-setup-order | │
-│check-start-date-not-used-in-defaults | check-system-tests-present | │
-│check-system-tests-tocs | check-urlparse-usage-in-code | check-xml | codespell | │
-│compile-www-assets | compile-www-assets-dev | create-missing-init-py-files-tests | │
-│debug-statements | detect-private-key | doctoc | end-of-file-fixer | fix-encoding-pragma│
-│| flynt | identity | insert-license | lint-chart-schema | lint-css | lint-dockerfile | │
-│lint-helm-chart | lint-json-schema | lint-markdown | lint-openapi | mixed-line-ending | │
-│mypy-core | mypy-dev | mypy-docs | mypy-providers | pretty-format-json | │
-│python-no-log-warn | replace-bad-characters | rst-backticks | ruff | shellcheck | │
-│trailing-whitespace | ts-compile-format-lint-www | update-black-version | │
-│update-breeze-cmd-output | update-breeze-readme-config-hash | │
-│update-common-sql-api-stubs | update-er-diagram | update-extras | │
-│update-in-the-wild-to-be-sorted | update-inlined-dockerfile-scripts | │
-│update-installed-providers-to-be-sorted | update-local-yml-file | │
-│update-migration-references | update-providers-dependencies | │
-│update-spelling-wordlist-to-be-sorted | update-supported-versions | │
-│update-vendored-in-k8s-json-schema | update-version | yamllint) │
-│--file-fList of files to run the checks on.(PATH)│
-│--all-files-aRun checks on all files.│
-│--show-diff-on-failure-sShow diff for files modified by the checks.│
-│--last-commit-cRun checks for all files in last commit. Mutually exclusive with --commit-ref.│
-│--commit-ref-rRun checks for this commit reference only (can be any git commit-ish reference). │
-│Mutually exclusive with --last-commit. │
-│(TEXT) │
-│--github-repository-gGitHub repository used to pull, push run images.(TEXT)[default: apache/airflow]│
-╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
-╭─ Common options ─────────────────────────────────────────────────────────────────────────────────────────────────────╮
-│--verbose-vPrint verbose information about performed steps.│
-│--dry-run-DIf dry-run is set, commands are only printed, not executed.│
-│--help-hShow this message and exit.│
-╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─ Pre-commit flags ───────────────────────────────────────────────────────────────────────────────────────────────────╮
+│--type-tType(s) of the static checks to run. │
+│(all | black | blacken-docs | check-airflow-config-yaml-consistent | │
+│check-airflow-provider-compatibility | check-apache-license-rat | │
+│check-base-operator-partial-arguments | check-base-operator-usage | │
+│check-boring-cyborg-configuration | check-breeze-top-dependencies-limited | │
+│check-builtin-literals | check-changelog-has-no-duplicates | │
+│check-core-deprecation-classes | check-daysago-import-from-utils | │
+│check-decorated-operator-implements-custom-name | check-docstring-param-types | │
+│check-example-dags-urls | check-executables-have-shebangs | │
+│check-extra-packages-references | check-extras-order | check-for-inclusive-language | │
+│check-hooks-apply | check-incorrect-use-of-LoggingMixin | check-init-decorator-arguments│
+│| check-lazy-logging | check-links-to-example-dags-do-not-use-hardcoded-versions | │
+│check-merge-conflict | check-newsfragments-are-valid | │
+│check-no-providers-in-core-examples | check-no-relative-imports | │
+│check-only-new-session-with-provide-session | │
+│check-persist-credentials-disabled-in-github-workflows | │
+│check-pre-commit-information-consistent | check-provide-create-sessions-imports | │
+│check-provider-yaml-valid | check-providers-init-file-missing | │
+│check-providers-subpackages-init-file-exist | check-pydevd-left-in-code | │
+│check-revision-heads-map | check-safe-filter-usage-in-html | check-setup-order | │
+│check-start-date-not-used-in-defaults | check-system-tests-present | │
+│check-system-tests-tocs | check-tests-unittest-testcase | check-urlparse-usage-in-code |│
+│check-xml | codespell | compile-www-assets | compile-www-assets-dev | │
+│create-missing-init-py-files-tests | debug-statements | detect-private-key | doctoc | │
+│end-of-file-fixer | fix-encoding-pragma | flynt | identity | insert-license | │
+│lint-chart-schema | lint-css | lint-dockerfile | lint-helm-chart | lint-json-schema | │
+│lint-markdown | lint-openapi | mixed-line-ending | mypy-core | mypy-dev | mypy-docs | │
+│mypy-providers | pretty-format-json | python-no-log-warn | replace-bad-characters | │
+│rst-backticks | ruff | shellcheck | trailing-whitespace | ts-compile-format-lint-www | │
+│update-black-version | update-breeze-cmd-output | update-breeze-readme-config-hash | │
+│update-common-sql-api-stubs | update-er-diagram | update-extras | │
+│update-in-the-wild-to-be-sorted | update-inlined-dockerfile-scripts | │
+│update-installed-providers-to-be-sorted | update-local-yml-file | │
+│update-migration-references | update-providers-dependencies | │
+│update-spelling-wordlist-to-be-sorted | update-supported-versions | │
+│update-vendored-in-k8s-json-schema | update-version | yamllint) │
+│--file-fList of files to run the checks on.(PATH)│
+│--all-files-aRun checks on all files.│
+│--show-diff-on-failure-sShow diff for files modified by the checks.│
+│--last-commit-cRun checks for all files in last commit. Mutually exclusive with --commit-ref.│
+│--commit-ref-rRun checks for this commit reference only (can be any git commit-ish reference). │
+│Mutually exclusive with --last-commit. │
+│(TEXT) │
+│--github-repository-gGitHub repository used to pull, push run images.(TEXT)[default: apache/airflow]│
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+╭─ Common options ─────────────────────────────────────────────────────────────────────────────────────────────────────╮
+│--verbose-vPrint verbose information about performed steps.│
+│--dry-run-DIf dry-run is set, commands are only printed, not executed.│
+│--help-hShow this message and exit.│
+╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
diff --git a/scripts/ci/pre_commit/pre_commit_unittest_testcase.py b/scripts/ci/pre_commit/pre_commit_unittest_testcase.py
new file mode 100755
index 0000000000000..c13c9a99258e2
--- /dev/null
+++ b/scripts/ci/pre_commit/pre_commit_unittest_testcase.py
@@ -0,0 +1,47 @@
+#!/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 pathlib
+import sys
+
+
+def check_test_file(file: str) -> int:
+ node = ast.parse(pathlib.Path(file).read_text("utf-8"), file)
+
+ found = 0
+ classes = [c for c in node.body if isinstance(c, ast.ClassDef)]
+ for c in classes:
+ # Some classes are returned as an ast.Attribute, some as an ast.Name object. Not quite sure why
+ parent_classes = [base.attr for base in c.bases if isinstance(base, ast.Attribute)]
+ parent_classes.extend([base.id for base in c.bases if isinstance(base, ast.Name)])
+
+ if "TestCase" in parent_classes:
+ found += 1
+ print(f"The class {c.name} inherits from TestCase, please use pytest instead")
+
+ return found
+
+
+def main(*args: str) -> int:
+ return sum([check_test_file(file) for file in args[1:]])
+
+
+if __name__ == "__main__":
+ sys.exit(main(*sys.argv))