Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions airflow-core/src/airflow/utils/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import signal
from collections.abc import Callable, Generator, Iterable, MutableMapping
from functools import cache
from typing import TYPE_CHECKING, Any, TypeVar, cast
from typing import TYPE_CHECKING, Any, TypeVar, cast, overload
from urllib.parse import urljoin

from lazy_object_proxy import Proxy
Expand All @@ -33,11 +33,16 @@
from airflow.utils.types import NOTSET

if TYPE_CHECKING:
from datetime import datetime
from typing import TypeGuard

import jinja2

from airflow.models.taskinstance import TaskInstance
from airflow.sdk.definitions.context import Context

CT = TypeVar("CT", str, datetime)

KEY_REGEX = re.compile(r"^[\w.-]+$")
GROUP_KEY_REGEX = re.compile(r"^[\w-]+$")
CAMELCASE_TO_SNAKE_CASE_REGEX = re.compile(r"(?!^)([A-Z]+)")
Expand Down Expand Up @@ -90,7 +95,15 @@ def handler(signum, frame):
signal.alarm(0)


def is_container(obj: Any) -> bool:
@overload
def is_container(obj: None | int | Iterable[int] | range) -> TypeGuard[Iterable[int]]: ...


@overload
def is_container(obj: None | CT | Iterable[CT]) -> TypeGuard[Iterable[CT]]: ...


def is_container(obj) -> bool:
"""Test if an object is a container (iterable) but not a string."""
if isinstance(obj, Proxy):
# Proxy of any object is considered a container because it implements __iter__
Expand Down