Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`)
Expand Down
46 changes: 43 additions & 3 deletions pandas/_config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,9 @@ def set_option(*args) -> None:

Parameters
----------
*args : str | object
*args : str | object | dict
Arguments provided in pairs, which will be interpreted as (pattern, value)
pairs.
pairs, or as a single dictionary containing multiple option-value pairs.
pattern: str
Regexp which should match a single option
value: object
Expand Down Expand Up @@ -248,11 +248,51 @@ def set_option(*args) -> None:
[2 rows x 5 columns]
>>> pd.reset_option("display.max_columns")
"""
# must at least 1 arg deal with constraints later
# 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

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this needed? does the next (existing) block not handle a single option-pair correctly?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing this out! I overlooked it when adding the dictionary handling. I'll remove it in the next commit.

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

Expand Down
23 changes: 22 additions & 1 deletion pandas/tests/config/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,28 @@ 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)
# Expect the deprecation warning
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):
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
Expand Down