Repository: dask/dask

Issue:
Deprecate method and limit from fillna
both of them are deprecated in pandas, so lets remove before we switch to dask-expr

Also lets deprecated downcast from bfill, ffill and fillna

Discussion:
github-actions[bot]: ## Unit Test Results
_See [test report](https://dask.github.io/dask/test_report.html) for an extended history of previous test failures. This is useful for diagnosing flaky tests._

     15 files  ±0       15 suites  ±0   3h 19m 31s :stopwatch: - 16m 17s
 12 968 tests ±0   11 912 :white_check_mark:  - 1     929 :zzz: ±0  127 :x: +1 
159 960 runs  ±0  142 561 :white_check_mark:  - 3  16 734 :zzz: +2  665 :x: +1 

For more details on these failures, see [this check](https://github.com/dask/dask/runs/20725248466).

Results for commit 3716f88d. ± Comparison against base commit 379e65b1.

[test-results]:data:application/gzip;base64,H4sIAF1brmUC/03NTRLCIAwF4Kt0WLsgFALxMg5SmGHsj0PLyvHuYivU5fuSvLxYiKNf2bUDdenYmuN2piEnu8Vl/mYgDYXKdNvngtDUfFuzc8cSiBMf8VmQBDUKNo77sW7kU1pSMV4k5fn4TYQ1t24pFELDoxtQ97LarxxRVfnvdss0xa0E1mvAYMwgtbaENHAC7rS6S4GGJNkA4LhHz94fiUYsNB0BAAA=

milesgranger: I don't think the dask-expr failures are releated 
https://github.com/dask/dask/actions/runs/7639745378/job/20813410074?pr=10846#step:8:27476 and also fails on main. 

Patch:
diff --git a/dask/dataframe/core.py b/dask/dataframe/core.py
index ca09cb9c8..e5b5a40bb 100644
--- a/dask/dataframe/core.py
+++ b/dask/dataframe/core.py
@@ -1880,6 +1880,7 @@ Dask Name: {name}, {layers}"""
         else:
             return self
 
+    @_deprecated_kwarg("method", None, comment="Use ffill or bfill instead.")
     @derived_from(pd.DataFrame)
     def fillna(self, value=None, method=None, limit=None, axis=None):
         if method is None and limit is not None:
diff --git a/dask/utils.py b/dask/utils.py
index b93ce9fa1..0da2953c8 100644
--- a/dask/utils.py
+++ b/dask/utils.py
@@ -148,6 +148,7 @@ def _deprecated_kwarg(
     new_arg_name: str | None = None,
     mapping: Mapping[Any, Any] | Callable[[Any], Any] | None = None,
     stacklevel: int = 2,
+    comment: str | None = None,
 ) -> Callable[[F], F]:
     """
     Decorator to deprecate a keyword argument of a function.
@@ -163,6 +164,9 @@ def _deprecated_kwarg(
         If mapping is present, use it to translate old arguments to
         new arguments. A callable must do its own value checking;
         values not found in a dict will be forwarded unchanged.
+    comment :  str, optional
+        Additional message to deprecation message. Useful to pass
+        on suggestions with the deprecation warning.
 
     Examples
     --------
@@ -215,6 +219,8 @@ def _deprecated_kwarg(
             "mapping from old to new argument values must be dict or callable!"
         )
 
+    comment_ = f"\n{comment}" or ""
+
     def _deprecated_kwarg(func: F) -> F:
         @wraps(func)
         def wrapper(*args, **kwargs) -> Callable[..., Any]:
@@ -226,7 +232,7 @@ def _deprecated_kwarg(
                         f"the {repr(old_arg_name)} keyword is deprecated and "
                         "will be removed in a future version. Please take "
                         f"steps to stop the use of {repr(old_arg_name)}"
-                    )
+                    ) + comment_
                     warnings.warn(msg, FutureWarning, stacklevel=stacklevel)
                     kwargs[old_arg_name] = old_arg_value
                     return func(*args, **kwargs)
@@ -248,7 +254,7 @@ def _deprecated_kwarg(
                         f"use {repr(new_arg_name)} instead."
                     )
 
-                warnings.warn(msg, FutureWarning, stacklevel=stacklevel)
+                warnings.warn(msg + comment_, FutureWarning, stacklevel=stacklevel)
                 if kwargs.get(new_arg_name) is not None:
                     msg = (
                         f"Can only specify {repr(old_arg_name)} "
diff --git a/pyproject.toml b/pyproject.toml
index 0359c3dc1..82b277a6b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -144,7 +144,6 @@ filterwarnings = [
     "ignore:Not prepending group keys:FutureWarning",
     "ignore:.*:dask.tests.warning_aliases.RemovedIn20Warning",
     "ignore:When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas:FutureWarning",
-    'ignore:DataFrameGroupBy\.apply operated on the grouping columns\. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation\. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning\.:FutureWarning',
     'ignore:Passing a BlockManager to DataFrame is deprecated and will raise in a future version. Use public APIs instead:DeprecationWarning',  # https://github.com/apache/arrow/issues/35081
     'ignore:The previous implementation of stack is deprecated and will be removed in a future version of pandas\.:FutureWarning',
     "ignore:Minimal version of pyarrow will soon be increased to 14.0.1",


Test patch:
diff --git a/dask/dataframe/io/tests/test_parquet.py b/dask/dataframe/io/tests/test_parquet.py
index 861b411fc..aab2c43ee 100644
--- a/dask/dataframe/io/tests/test_parquet.py
+++ b/dask/dataframe/io/tests/test_parquet.py
@@ -789,7 +789,8 @@ def test_append_create(tmpdir, engine):
     assert_eq(df, ddf3)
 
 
-def test_append_with_partition(tmpdir, engine):
+@PYARROW_MARK
+def test_append_with_partition(tmpdir):
     tmp = str(tmpdir)
     df0 = pd.DataFrame(
         {
@@ -816,18 +817,18 @@ def test_append_with_partition(tmpdir, engine):
 
     dd_df0 = dd.from_pandas(df0, npartitions=1)
     dd_df1 = dd.from_pandas(df1, npartitions=1)
-    dd.to_parquet(dd_df0, tmp, partition_on=["lon"], engine=engine)
+    dd.to_parquet(dd_df0, tmp, partition_on=["lon"], engine="pyarrow")
     dd.to_parquet(
         dd_df1,
         tmp,
         partition_on=["lon"],
         append=True,
         ignore_divisions=True,
-        engine=engine,
+        engine="pyarrow",
     )
 
     out = dd.read_parquet(
-        tmp, engine=engine, index="index", calculate_divisions=True
+        tmp, engine="pyarrow", index="index", calculate_divisions=True
     ).compute()
     # convert categorical to plain int just to pass assert
     out["lon"] = out.lon.astype("int64")
diff --git a/dask/dataframe/tests/test_dataframe.py b/dask/dataframe/tests/test_dataframe.py
index 808af64eb..52c29ba7a 100644
--- a/dask/dataframe/tests/test_dataframe.py
+++ b/dask/dataframe/tests/test_dataframe.py
@@ -2645,6 +2645,10 @@ def test_fillna():
         pytest.raises(NotImplementedError, lambda: ddf.fillna(0, limit=10))
         pytest.raises(NotImplementedError, lambda: ddf.fillna(0, limit=10, axis=1))
 
+    if not DASK_EXPR_ENABLED:
+        with pytest.warns(FutureWarning, match="'method' keyword is deprecated"):
+            ddf.fillna(method="ffill")
+
 
 def test_ffill():
     df = _compat.makeMissingDataframe()