This is an automated email from the ASF dual-hosted git repository.

shahar1 pushed a commit to branch check-core-shim-targets-exist
in repository https://gitbox.apache.org/repos/asf/airflow.git

commit 9a4cc1ce2e30556d6c052d28e3a4fca774781761
Author: Shahar Epstein <[email protected]>
AuthorDate: Sun Nov 8 15:06:45 2026 +0200

    Treat the else branch of "if not TYPE_CHECKING" as typing-only
    
    The guard counted names bound under the else branch of
    `if not TYPE_CHECKING` as present at runtime, so a shim target defined
    only there would pass the check although it cannot be imported. That
    branch is now skipped and only the body is collected.
---
 scripts/ci/prek/check_core_shim_targets_exist.py            | 7 +++++++
 scripts/tests/ci/prek/test_check_core_shim_targets_exist.py | 7 +++++++
 2 files changed, 14 insertions(+)

diff --git a/scripts/ci/prek/check_core_shim_targets_exist.py 
b/scripts/ci/prek/check_core_shim_targets_exist.py
index 12f204bc338..ff967ff7f15 100755
--- a/scripts/ci/prek/check_core_shim_targets_exist.py
+++ b/scripts/ci/prek/check_core_shim_targets_exist.py
@@ -106,6 +106,13 @@ def get_module_names(path: Path) -> set[str]:
                 names.update(alias.asname or alias.name.split(".")[0] for 
alias in node.names)
             elif isinstance(node, ast.If):
                 # Version-gated branches cannot be resolved statically, so 
either branch counts.
+                if (
+                    isinstance(node.test, ast.UnaryOp)
+                    and isinstance(node.test.op, ast.Not)
+                    and is_type_checking(node.test.operand)
+                ):
+                    collect(node.body)
+                    continue
                 if not is_type_checking(node.test):
                     collect(node.body)
                 collect(node.orelse)
diff --git a/scripts/tests/ci/prek/test_check_core_shim_targets_exist.py 
b/scripts/tests/ci/prek/test_check_core_shim_targets_exist.py
index 8baf8397611..3ed6fc38be9 100644
--- a/scripts/tests/ci/prek/test_check_core_shim_targets_exist.py
+++ b/scripts/tests/ci/prek/test_check_core_shim_targets_exist.py
@@ -54,6 +54,11 @@ def providers_root(tmp_path):
             class WaitSensor(Base): ...
 
             def helper(): ...
+
+            if not TYPE_CHECKING:
+                class Runtime: ...
+            else:
+                class TypingOnly: ...
             """
         )
     )
@@ -91,6 +96,8 @@ def 
test_find_provider_targets_skips_non_provider_targets(write_python_file):
         pytest.param("WaitSensorAsync", f"{MODULE}.WaitSensorAsync", False, 
id="removed-class"),
         pytest.param("*", "airflow.providers.acme.sensors.gone", False, 
id="removed-module"),
         pytest.param("TypeOnly", f"{MODULE}.TypeOnly", False, 
id="type-checking-only"),
+        pytest.param("Runtime", f"{MODULE}.Runtime", True, 
id="not-type-checking-body"),
+        pytest.param("TypingOnly", f"{MODULE}.TypingOnly", False, 
id="not-type-checking-else"),
         pytest.param("annotated_only", f"{MODULE}.annotated_only", False, 
id="annotation-without-value"),
         pytest.param("X", "airflow.providers.missing.hooks.X", False, 
id="missing-provider"),
     ],

Reply via email to