- case: test_mypy_pipe_lambda_noarg_return_type
  main: |
    from xarray import Dataset

    ds = Dataset().pipe(lambda data: data)

    reveal_type(ds)  # N: Revealed type is "xarray.core.dataset.Dataset"

- case: test_mypy_pipe_lambda_posarg_return_type
  main: |
    from xarray import Dataset

    ds = Dataset().pipe(lambda data, arg: arg, "foo")

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

- case: test_mypy_pipe_lambda_chaining_return_type
  main: |
    from xarray import Dataset

    answer = Dataset().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 Dataset

    # Call to pipe missing argument for lambda parameter `arg`
    ds = Dataset().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[[Dataset, **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 Dataset

    # Call to pipe with extra argument for lambda
    ds = Dataset().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[[Dataset, **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 Dataset

    def f(ds: Dataset, arg: int) -> Dataset:
        return ds

    # Call to pipe missing argument for function parameter `arg`
    ds = Dataset().pipe(f)
  out: |
    main:7: error: No overload variant of "pipe" of "DataWithCoords" matches argument type "Callable[[Dataset, int], Dataset]"  [call-overload]
    main:7: note: Possible overload variants:
    main:7: note:     def [P`2, T] pipe(self, func: Callable[[Dataset, **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 Dataset

    def f(ds: Dataset, arg: int) -> Dataset:
        return ds

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

    def f(ds: Dataset, arg: int, *, kwonly: int) -> Dataset:
        return ds

    # Call to pipe missing argument for kwonly parameter `kwonly`
    ds = Dataset().pipe(f, 42)
  out: |
    main:7: error: No overload variant of "pipe" of "DataWithCoords" matches argument types "Callable[[Dataset, int, NamedArg(int, 'kwonly')], Dataset]", "int"  [call-overload]
    main:7: note: Possible overload variants:
    main:7: note:     def [P`2, T] pipe(self, func: Callable[[Dataset, **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 Dataset

    def f(ds: Dataset, arg: int, *, kwonly: int) -> Dataset:
        return ds

    # Call to pipe missing keyword for kwonly parameter `kwonly`
    ds = Dataset().pipe(f, 42, 99)
  out: |
    main:7: error: No overload variant of "pipe" of "DataWithCoords" matches argument types "Callable[[Dataset, int, NamedArg(int, 'kwonly')], Dataset]", "int", "int"  [call-overload]
    main:7: note: Possible overload variants:
    main:7: note:     def [P`2, T] pipe(self, func: Callable[[Dataset, **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.1 outputs "defined here" notes without line numbers that pytest-mypy-plugins can't parse
  # See: https://github.com/python/mypy/issues/19257 (mypy issue about missing line numbers)
  main: |
    from xarray import Dataset

    def f(ds: Dataset, arg: int, *, kwonly: int) -> Dataset:
        return ds

    # Call to pipe using wrong keyword: `kw` instead of `kwonly`
    ds = Dataset().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 a "defined here" note that pytest-mypy-plugins can't parse

- case: test_mypy_pipe_tuple_return_type_dataset
  main: |
    from xarray import Dataset

    def f(arg: int, ds: Dataset) -> Dataset:
        return ds

    ds = Dataset().pipe((f, "ds"), 42)
    reveal_type(ds)  # N: Revealed type is "xarray.core.dataset.Dataset"

- case: test_mypy_pipe_tuple_return_type_other
  main: |
    from xarray import Dataset

    def f(arg: int, ds: Dataset) -> int:
        return arg

    answer = Dataset().pipe((f, "ds"), 42)

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

- case: test_mypy_pipe_tuple_missing_arg
  main: |
    from xarray import Dataset

    def f(arg: int, ds: Dataset) -> Dataset:
        return ds

    # 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.

    ds = Dataset().pipe((f, "ds"))
    reveal_type(ds)  # N: Revealed type is "xarray.core.dataset.Dataset"

    # 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`.

    ds = Dataset().pipe(lambda data, arg: f(arg, data))
  out: |
    main:17: error: No overload variant of "pipe" of "DataWithCoords" matches argument type "Callable[[Any, Any], Dataset]"  [call-overload]
    main:17: note: Possible overload variants:
    main:17: note:     def [P`9, T] pipe(self, func: Callable[[Dataset, **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 Dataset

    def f(arg: int, ds: Dataset) -> Dataset:
        return ds

    # 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.

    ds = Dataset().pipe((f, "ds"), 42, "foo")
    reveal_type(ds)  # N: Revealed type is "xarray.core.dataset.Dataset"

    # 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.

    ds = Dataset().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], Dataset]", "int", "str"  [call-overload]
    main:17: note: Possible overload variants:
    main:17: note:     def [P`9, T] pipe(self, func: Callable[[Dataset, **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
