diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index b4aa6447c0a1b..579320b723a77 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -52,6 +52,7 @@ Other enhancements - :class:`Rolling` and :class:`Expanding` now support ``pipe`` method (:issue:`57076`) - :class:`Series` now supports the Arrow PyCapsule Interface for export (:issue:`59518`) - :func:`DataFrame.to_excel` argument ``merge_cells`` now accepts a value of ``"columns"`` to only merge :class:`MultiIndex` column header header cells (:issue:`35384`) +- :func:`set_option` now accepts a dictionary of options, simplifying configuration of multiple settings at once (:issue:`61093`) - :meth:`DataFrame.corrwith` now accepts ``min_periods`` as optional arguments, as in :meth:`DataFrame.corr` and :meth:`Series.corr` (:issue:`9490`) - :meth:`DataFrame.cummin`, :meth:`DataFrame.cummax`, :meth:`DataFrame.cumprod` and :meth:`DataFrame.cumsum` methods now have a ``numeric_only`` parameter (:issue:`53072`) - :meth:`DataFrame.ewm` now allows ``adjust=False`` when ``times`` is provided (:issue:`54328`) @@ -419,6 +420,7 @@ Other Deprecations - Deprecated lowercase strings ``d``, ``b`` and ``c`` denoting frequencies in :class:`Day`, :class:`BusinessDay` and :class:`CustomBusinessDay` in favour of ``D``, ``B`` and ``C`` (:issue:`58998`) - Deprecated lowercase strings ``w``, ``w-mon``, ``w-tue``, etc. denoting frequencies in :class:`Week` in favour of ``W``, ``W-MON``, ``W-TUE``, etc. (:issue:`58998`) - Deprecated parameter ``method`` in :meth:`DataFrame.reindex_like` / :meth:`Series.reindex_like` (:issue:`58667`) +- Deprecated passing multiple option-value pairs parameter in :meth:`DataFrame.set_option` (:issue:`61093`) - Deprecated strings ``w``, ``d``, ``MIN``, ``MS``, ``US`` and ``NS`` denoting units in :class:`Timedelta` in favour of ``W``, ``D``, ``min``, ``ms``, ``us`` and ``ns`` (:issue:`59051`) - Deprecated using ``epoch`` date format in :meth:`DataFrame.to_json` and :meth:`Series.to_json`, use ``iso`` instead. (:issue:`57063`) diff --git a/pandas/_config/config.py b/pandas/_config/config.py index ce53e05608ba7..148f75a5556a3 100644 --- a/pandas/_config/config.py +++ b/pandas/_config/config.py @@ -199,9 +199,9 @@ def set_option(*args) -> None: Parameters ---------- - *args : str | object - Arguments provided in pairs, which will be interpreted as (pattern, value) - pairs. + *args : str | object | dict + Arguments provided in a pair, which will be interpreted as (pattern, value), + or as a single dictionary containing multiple option-value pairs. pattern: str Regexp which should match a single option value: object @@ -239,6 +239,8 @@ def set_option(*args) -> None: Examples -------- + Option-Value Pair Input: + >>> pd.set_option("display.max_columns", 4) >>> df = pd.DataFrame([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]) >>> df @@ -247,12 +249,64 @@ def set_option(*args) -> None: 1 6 7 ... 9 10 [2 rows x 5 columns] >>> pd.reset_option("display.max_columns") - """ - # must at least 1 arg deal with constraints later + + Dictionary Input: + + >>> pd.set_option({"display.max_columns": 4, "display.precision": 1}) + >>> df = pd.DataFrame([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]) + >>> df + 0 1 ... 3 4 + 0 1 2 ... 4 5 + 1 6 7 ... 9 10 + [2 rows x 5 columns] + >>> pd.reset_option("display.max_columns") + >>> pd.reset_option("display.precision") + """ + # Handle dictionary input + if len(args) == 1 and isinstance(args[0], dict): + options_dict = args[0] + for k, v in options_dict.items(): + key = _get_single_key(k) + opt = _get_registered_option(key) + if opt and opt.validator: + opt.validator(v) + # walk the nested dict + root, k_root = _get_root(key) + root[k_root] = v + if opt.cb: + opt.cb(key) + return + + # Handle single option-value pair + if len(args) == 2: + key = _get_single_key(args[0]) + v = args[1] + + opt = _get_registered_option(key) + if opt and opt.validator: + opt.validator(v) + + # walk the nested dict + root, k_root = _get_root(key) + root[k_root] = v + + if opt.cb: + opt.cb(key) + return + + # Deprecated (# GH 61093): multiple option-value pairs as separate arguments nargs = len(args) if not nargs or nargs % 2 != 0: raise ValueError("Must provide an even number of non-keyword arguments") + warnings.warn( + "Setting multiple options using multiple arguments is deprecated and will be " + "removed in a future version. Use a dictionary instead.", + FutureWarning, + stacklevel=2, + ) + + # Backward compatibility for k, v in zip(args[::2], args[1::2]): key = _get_single_key(k) diff --git a/pandas/tests/config/test_config.py b/pandas/tests/config/test_config.py index aaf6178866ecd..62db61d7f2676 100644 --- a/pandas/tests/config/test_config.py +++ b/pandas/tests/config/test_config.py @@ -189,7 +189,29 @@ def test_set_option_multiple(self): assert cf.get_option("b.c") == "hullo" assert cf.get_option("b.b") is None - cf.set_option("a", "2", "b.c", None, "b.b", 10.0) + with tm.assert_produces_warning( + FutureWarning, + match="Setting multiple options using multiple arguments is deprecated", + ): + cf.set_option("a", "2", "b.c", None, "b.b", 10.0) + + assert cf.get_option("a") == "2" + assert cf.get_option("b.c") is None + assert cf.get_option("b.b") == 10.0 + + def test_set_option_dict(self): + # GH 61093 + + cf.register_option("a", 1, "doc") + cf.register_option("b.c", "hullo", "doc2") + cf.register_option("b.b", None, "doc2") + + assert cf.get_option("a") == 1 + assert cf.get_option("b.c") == "hullo" + assert cf.get_option("b.b") is None + + options_dict = {"a": "2", "b.c": None, "b.b": 10.0} + cf.set_option(options_dict) assert cf.get_option("a") == "2" assert cf.get_option("b.c") is None