Repository: apache/airflow
File: providers/microsoft/azure/src/airflow/providers/microsoft/azure/hooks/msgraph.py (Python)

Code before:
from kiota_abstractions.response_handler import ResponseHandler
from kiota_abstractions.serialization import ParseNodeFactoryRegistry
from kiota_authentication_azure.azure_identity_authentication_provider import (
    AzureIdentityAuthenticationProvider,
)
from kiota_http.httpx_request_adapter import HttpxRequestAdapter
from kiota_http.middleware.options import ResponseHandlerOption
from kiota_serialization_json.json_parse_node_factory import JsonParseNodeFactory
from kiota_serialization_text.text_parse_node_factory import TextParseNodeFactory
from msgraph_core import APIVersion, GraphClientFactory
from msgraph_core._enums import NationalClouds

from airflow.exceptions import AirflowBadRequest, AirflowConfigException, AirflowProviderDeprecationWarning
from airflow.providers.common.compat.sdk import AirflowException, AirflowNotFoundException, BaseHook

if TYPE_CHECKING:
    from azure.identity._internal.client_credential_base import ClientCredentialBase
    from kiota_abstractions.request_adapter import RequestAdapter
    from kiota_abstractions.response_handler import NativeResponseType
    from kiota_abstractions.serialization import ParsableFactory

    from airflow.providers.common.compat.sdk import Connection
    from airflow.sdk._shared.secrets_masker import redact
else:
    try:
        from airflow.sdk._shared.secrets_masker import redact
    except ImportError:
        from airflow.sdk.execution_time.secrets_masker import redact


PaginationCallable = Callable[..., tuple[str, dict[str, Any] | None]]


def execute_callable(func: Callable, *args: Any, **kwargs: Any) -> Any:
    """Dynamically call a function by matching its signature to provided args/kwargs."""
    sig = inspect.signature(func)
    accepts_kwargs = any(p.kind == inspect.Parameter.VAR_KEYWORD for p in sig.parameters.values())

    if not accepts_kwargs:
        # Only pass arguments the function explicitly declares
        filtered_kwargs = {k: v for k, v in kwargs.items() if k in sig.parameters}
    else:
        filtered_kwargs = kwargs

    try:
        sig.bind(*args, **filtered_kwargs)
    except TypeError as err:
        raise TypeError(
            f"Failed to bind arguments to function {func.__name__}: {err}\n"
            f"Expected parameters: {list(sig.parameters.keys())}\n"
            f"Provided kwargs: {list(kwargs.keys())}"

Review comment (suggestion):
I do not like this. Can't we use the `airflow.providers.common.compat.sdk ` module here? Mind you that you might need to re export `redact` in: `task-sdk/src/airflow/sdk/log.py` and use that path instead.

Code after:
from kiota_abstractions.response_handler import ResponseHandler
from kiota_abstractions.serialization import ParseNodeFactoryRegistry
from kiota_authentication_azure.azure_identity_authentication_provider import (
    AzureIdentityAuthenticationProvider,
)
from kiota_http.httpx_request_adapter import HttpxRequestAdapter
from kiota_http.middleware.options import ResponseHandlerOption
from kiota_serialization_json.json_parse_node_factory import JsonParseNodeFactory
from kiota_serialization_text.text_parse_node_factory import TextParseNodeFactory
from msgraph_core import APIVersion, GraphClientFactory
from msgraph_core._enums import NationalClouds

from airflow.exceptions import AirflowBadRequest, AirflowConfigException, AirflowProviderDeprecationWarning
from airflow.providers.common.compat.sdk import AirflowException, AirflowNotFoundException, BaseHook

if TYPE_CHECKING:
    from azure.identity._internal.client_credential_base import ClientCredentialBase
    from kiota_abstractions.request_adapter import RequestAdapter
    from kiota_abstractions.response_handler import NativeResponseType
    from kiota_abstractions.serialization import ParsableFactory

    from airflow.providers.common.compat.sdk import Connection

from airflow.providers.common.compat.sdk import redact

PaginationCallable = Callable[..., tuple[str, dict[str, Any] | None]]


def execute_callable(func: Callable, *args: Any, **kwargs: Any) -> Any:
    """Dynamically call a function by matching its signature to provided args/kwargs."""
    sig = inspect.signature(func)
    accepts_kwargs = any(p.kind == inspect.Parameter.VAR_KEYWORD for p in sig.parameters.values())

    if not accepts_kwargs:
        # Only pass arguments the function explicitly declares
        filtered_kwargs = {k: v for k, v in kwargs.items() if k in sig.parameters}
    else:
        filtered_kwargs = kwargs

    try:
        sig.bind(*args, **filtered_kwargs)
    except TypeError as err:
        raise TypeError(
            f"Failed to bind arguments to function {func.__name__}: {err}\n"
            f"Expected parameters: {list(sig.parameters.keys())}\n"
            f"Provided kwargs: {list(kwargs.keys())}"
        ) from err

    return func(*args, **filtered_kwargs)