- case: test_mypy_pipe_lambda_noarg_return_type
  main: |
    from xarray import DataArray

    da = DataArray().pipe(lambda data: data)

    reveal_type(da)  # N: Revealed type is "xarray.core.dataarray.DataArray"

- case: test_mypy_pipe_lambda_posarg_return_type
  main: |
    from xarray import DataArray

    da = DataArray().pipe(lambda data, arg: arg, "foo")

    reveal_type(da)  # N: Revealed type is "builtins.str"

- case: test_mypy_pipe_lambda_chaining_return_type
  main: |
    from xarray import DataArray

    answer = DataArray().pipe(lambda data, arg: arg, "foo").count("o")

    reveal_type(answer)  # N: Revealed type is "builtins.int"

- case: test_mypy_pipe_lambda_missing_arg
  main: |
    from xarray import DataArray

    # Call to pipe missing argument for lambda parameter `arg`
    da = DataArray().pipe(lambda data, arg: data)
  out: |
    main:4: error: No overload variant of "pipe" of "DataWithCoords" matches argument type "Callable[[Any, Any], Any]"  [call-overload]
    main:4: note: Possible overload variants:
    main:4: note:     def [P`2, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
    main:4: note:     def [T] pipe(self, func: tuple[Callable[..., T], str], *args: Any, **kwargs: Any) -> T

- case: test_mypy_pipe_lambda_extra_arg
  main: |
    from xarray import DataArray

    # Call to pipe with extra argument for lambda
    da = DataArray().pipe(lambda data: data, "oops!")
  out: |
    main:4: error: No overload variant of "pipe" of "DataWithCoords" matches argument types "Callable[[Any], Any]", "str"  [call-overload]
    main:4: note: Possible overload variants:
    main:4: note:     def [P`2, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
    main:4: note:     def [T] pipe(self, func: tuple[Callable[..., T], str], *args: Any, **kwargs: Any) -> T

- case: test_mypy_pipe_function_missing_posarg
  main: |
    from xarray import DataArray

    def f(da: DataArray, arg: int) -> DataArray:
        return da

    # Call to pipe missing argument for function parameter `arg`
    da = DataArray().pipe(f)
  out: |
    main:7: error: No overload variant of "pipe" of "DataWithCoords" matches argument type "Callable[[DataArray, int], DataArray]"  [call-overload]
    main:7: note: Possible overload variants:
    main:7: note:     def [P`2, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
    main:7: note:     def [T] pipe(self, func: tuple[Callable[..., T], str], *args: Any, **kwargs: Any) -> T

- case: test_mypy_pipe_function_extra_posarg
  main: |
    from xarray import DataArray

    def f(da: DataArray, arg: int) -> DataArray:
        return da

    # Call to pipe missing keyword for kwonly parameter `kwonly`
    da = DataArray().pipe(f, 42, "oops!")
  out: |
    main:7: error: No overload variant of "pipe" of "DataWithCoords" matches argument types "Callable[[DataArray, int], DataArray]", "int", "str"  [call-overload]
    main:7: note: Possible overload variants:
    main:7: note:     def [P`2, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
    main:7: note:     def [T] pipe(self, func: tuple[Callable[..., T], str], *args: Any, **kwargs: Any) -> T

- case: test_mypy_pipe_function_missing_kwarg
  main: |
    from xarray import DataArray

    def f(da: DataArray, arg: int, *, kwonly: int) -> DataArray:
        return da

    # Call to pipe missing argument for kwonly parameter `kwonly`
    da = DataArray().pipe(f, 42)
  out: |
    main:7: error: No overload variant of "pipe" of "DataWithCoords" matches argument types "Callable[[DataArray, int, NamedArg(int, 'kwonly')], DataArray]", "int"  [call-overload]
    main:7: note: Possible overload variants:
    main:7: note:     def [P`2, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
    main:7: note:     def [T] pipe(self, func: tuple[Callable[..., T], str], *args: Any, **kwargs: Any) -> T

- case: test_mypy_pipe_function_missing_keyword
  main: |
    from xarray import DataArray

    def f(da: DataArray, arg: int, *, kwonly: int) -> DataArray:
        return da

    # Call to pipe missing keyword for kwonly parameter `kwonly`
    da = DataArray().pipe(f, 42, 99)
  out: |
    main:7: error: No overload variant of "pipe" of "DataWithCoords" matches argument types "Callable[[DataArray, int, NamedArg(int, 'kwonly')], DataArray]", "int", "int"  [call-overload]
    main:7: note: Possible overload variants:
    main:7: note:     def [P`2, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
    main:7: note:     def [T] pipe(self, func: tuple[Callable[..., T], str], *args: Any, **kwargs: Any) -> T

- case: test_mypy_pipe_function_unexpected_keyword
  skip: True # mypy 1.18+ outputs "defined here" notes without line numbers (e.g., "xarray/core/common.py: note:...")
  # pytest-mypy-plugins expects all lines to match "file:line: severity: message" format and can't parse these notes.
  # This is a mypy behavior, not a bug. The test would need pytest-mypy-plugins to support notes without line numbers.
  main: |
    from xarray import DataArray

    def f(da: DataArray, arg: int, *, kwonly: int) -> DataArray:
        return da

    # Call to pipe using wrong keyword: `kw` instead of `kwonly`
    da = DataArray().pipe(f, 42, kw=99)
  out: |
    main:7: error: Unexpected keyword argument "kw" for "pipe" of "DataWithCoords"  [call-arg]
    # Note: mypy 1.18.1 also outputs: xarray/core/common: note: "pipe" of "DataWithCoords" defined here

- case: test_mypy_pipe_tuple_return_type_dataarray
  main: |
    from xarray import DataArray

    def f(arg: int, da: DataArray) -> DataArray:
        return da

    da = DataArray().pipe((f, "da"), 42)
    reveal_type(da)  # N: Revealed type is "xarray.core.dataarray.DataArray"

- case: test_mypy_pipe_tuple_return_type_other
  main: |
    from xarray import DataArray

    def f(arg: int, da: DataArray) -> int:
        return arg

    answer = DataArray().pipe((f, "da"), 42)

    reveal_type(answer)  # N: Revealed type is "builtins.int"

- case: test_mypy_pipe_tuple_missing_arg
  main: |
    from xarray import DataArray

    def f(arg: int, da: DataArray) -> DataArray:
        return da

    # Since we cannot provide a precise type annotation when passing a tuple to
    # pipe, there's not enough information for type analysis to indicate that
    # we are missing an argument for parameter `arg`, so we get no error here.

    da = DataArray().pipe((f, "da"))
    reveal_type(da)  # N: Revealed type is "xarray.core.dataarray.DataArray"

    # Rather than passing a tuple, passing a lambda that calls `f` with args in
    # the correct order allows for proper type analysis, indicating (perhaps
    # somewhat cryptically) that we failed to pass an argument for `arg`.

    da = DataArray().pipe(lambda data, arg: f(arg, data))
  out: |
    main:17: error: No overload variant of "pipe" of "DataWithCoords" matches argument type "Callable[[Any, Any], DataArray]"  [call-overload]
    main:17: note: Possible overload variants:
    main:17: note:     def [P`9, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
    main:17: note:     def [T] pipe(self, func: tuple[Callable[..., T], str], *args: Any, **kwargs: Any) -> T

- case: test_mypy_pipe_tuple_extra_arg
  main: |
    from xarray import DataArray

    def f(arg: int, da: DataArray) -> DataArray:
        return da

    # Since we cannot provide a precise type annotation when passing a tuple to
    # pipe, there's not enough information for type analysis to indicate that
    # we are providing too many args for `f`, so we get no error here.

    da = DataArray().pipe((f, "da"), 42, "foo")
    reveal_type(da)  # N: Revealed type is "xarray.core.dataarray.DataArray"

    # Rather than passing a tuple, passing a lambda that calls `f` with args in
    # the correct order allows for proper type analysis, indicating (perhaps
    # somewhat cryptically) that we passed too many arguments.

    da = DataArray().pipe(lambda data, arg: f(arg, data), 42, "foo")
  out: |
    main:17: error: No overload variant of "pipe" of "DataWithCoords" matches argument types "Callable[[Any, Any], DataArray]", "int", "str"  [call-overload]
    main:17: note: Possible overload variants:
    main:17: note:     def [P`9, T] pipe(self, func: Callable[[DataArray, **P], T], *args: P.args, **kwargs: P.kwargs) -> T
    main:17: note:     def [T] pipe(self, func: tuple[Callable[..., T], str], *args: Any, **kwargs: Any) -> T
