Skip to content

Commit 09df295

Browse files
committed
Merge pull request #3677 from cpcloud/option-syntax-enh-3667
ENH: enhance set_option syntax
2 parents 31512a2 + 0cb981c commit 09df295

File tree

4 files changed

+108
-13
lines changed

4 files changed

+108
-13
lines changed

RELEASE.rst

+4
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ pandas 0.11.1
4646
Note: The default value will change in 0.12 to make the default *to* write and
4747
read multi-index columns in the new format. (GH3571_, GH1651_, GH3141_)
4848
- Add iterator to ``Series.str`` (GH3638_)
49+
- ``pd.set_option()`` now allows N option, value pairs (GH3667_).
50+
51+
4952

5053
**Improvements to existing features**
5154

@@ -269,6 +272,7 @@ pandas 0.11.1
269272
.. _GH3702: https://github.com/pydata/pandas/issues/3702
270273
.. _GH3691: https://github.com/pydata/pandas/issues/3691
271274
.. _GH3696: https://github.com/pydata/pandas/issues/3696
275+
.. _GH3667: https://github.com/pydata/pandas/issues/3667
272276

273277
pandas 0.11.0
274278
=============

doc/source/v0.11.1.txt

+25
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,30 @@ Enhancements
238238
GH3572_). This happens before any drawing takes place which elimnates any
239239
spurious plots from showing up.
240240

241+
- ``pd.set_option()`` now allows N option, value pairs (GH3667_).
242+
243+
Let's say that we had an option ``'a.b'`` and another option ``'b.c'``.
244+
We can set them at the same time:
245+
246+
.. ipython:: python
247+
:suppress:
248+
249+
pd.core.config.register_option('a.b', 2, 'ay dot bee')
250+
pd.core.config.register_option('b.c', 3, 'bee dot cee')
251+
252+
.. ipython:: python
253+
254+
pd.get_option('a.b')
255+
pd.get_option('b.c')
256+
pd.set_option('a.b', 1, 'b.c', 4)
257+
pd.get_option('a.b')
258+
pd.get_option('b.c')
259+
260+
You can of course still do it sequentially if you want. You can use up to
261+
N arguments here, the only stipulation is that the number of arguments
262+
must be even (since if they weren't then that would mean you provided an
263+
argument name with no value).
264+
241265
Bug Fixes
242266
~~~~~~~~~
243267

@@ -305,3 +329,4 @@ on GitHub for a complete list.
305329
.. _GH3702: https://github.com/pydata/pandas/issues/3702
306330
.. _GH3691: https://github.com/pydata/pandas/issues/3691
307331
.. _GH3696: https://github.com/pydata/pandas/issues/3696
332+
.. _GH3667: https://github.com/pydata/pandas/issues/3667

pandas/core/config.py

+41-13
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def _get_option(pat, silent=False):
9494
return root[k]
9595

9696

97-
def _set_option(pat, value, silent=False):
97+
def _set_single_option(pat, value, silent):
9898
key = _get_single_key(pat, silent)
9999

100100
o = _get_registered_option(key)
@@ -109,6 +109,40 @@ def _set_option(pat, value, silent=False):
109109
o.cb(key)
110110

111111

112+
def _set_multiple_options(args, silent):
113+
for k, v in zip(args[::2], args[1::2]):
114+
_set_single_option(k, v, silent)
115+
116+
117+
def _set_option(*args, **kwargs):
118+
# must at least 1 arg deal with constraints later
119+
nargs = len(args)
120+
if not nargs or nargs % 2 != 0:
121+
raise AssertionError("Must provide an even number of non-keyword "
122+
"arguments")
123+
124+
# must be 0 or 1 kwargs
125+
nkwargs = len(kwargs)
126+
if nkwargs not in (0, 1):
127+
raise AssertionError("The can only be 0 or 1 keyword arguments")
128+
129+
# if 1 kwarg then it must be silent=True or silent=False
130+
if nkwargs:
131+
k, = kwargs.keys()
132+
v, = kwargs.values()
133+
134+
if k != 'silent':
135+
raise ValueError("the only allowed keyword argument is 'silent', "
136+
"you passed '{0}'".format(k))
137+
if not isinstance(v, bool):
138+
raise TypeError("the type of the keyword argument passed must be "
139+
"bool, you passed a {0}".format(v.__class__))
140+
141+
# default to false
142+
silent = kwargs.get('silent', False)
143+
_set_multiple_options(args, silent)
144+
145+
112146
def _describe_option(pat='', _print_desc=True):
113147

114148
keys = _select_options(pat)
@@ -186,7 +220,7 @@ def __dir__(self):
186220
# of options, and option descriptions.
187221

188222

189-
class CallableDyanmicDoc(object):
223+
class CallableDynamicDoc(object):
190224

191225
def __init__(self, func, doc_tmpl):
192226
self.__doc_tmpl__ = doc_tmpl
@@ -301,10 +335,10 @@ def __doc__(self):
301335

302336
# bind the functions with their docstrings into a Callable
303337
# and use that as the functions exposed in pd.api
304-
get_option = CallableDyanmicDoc(_get_option, _get_option_tmpl)
305-
set_option = CallableDyanmicDoc(_set_option, _set_option_tmpl)
306-
reset_option = CallableDyanmicDoc(_reset_option, _reset_option_tmpl)
307-
describe_option = CallableDyanmicDoc(_describe_option, _describe_option_tmpl)
338+
get_option = CallableDynamicDoc(_get_option, _get_option_tmpl)
339+
set_option = CallableDynamicDoc(_set_option, _set_option_tmpl)
340+
reset_option = CallableDynamicDoc(_reset_option, _reset_option_tmpl)
341+
describe_option = CallableDynamicDoc(_describe_option, _describe_option_tmpl)
308342
options = DictWrapper(_global_config)
309343

310344
######################################################
@@ -505,13 +539,7 @@ def _get_registered_option(key):
505539
-------
506540
RegisteredOption (namedtuple) if key is deprecated, None otherwise
507541
"""
508-
509-
try:
510-
d = _registered_options[key]
511-
except KeyError:
512-
return None
513-
else:
514-
return d
542+
return _registered_options.get(key)
515543

516544

517545
def _translate_key(key):

pandas/tests/test_config.py

+38
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,44 @@ def test_set_option(self):
169169

170170
self.assertRaises(KeyError, self.cf.set_option, 'no.such.key', None)
171171

172+
173+
def test_set_option_empty_args(self):
174+
self.assertRaises(AssertionError, self.cf.set_option)
175+
176+
def test_set_option_uneven_args(self):
177+
self.assertRaises(AssertionError, self.cf.set_option, 'a.b', 2, 'b.c')
178+
179+
180+
def test_set_option_2_kwargs(self):
181+
self.assertRaises(AssertionError, self.cf.set_option, 'a.b', 2,
182+
silenadf=2, asdf=2)
183+
184+
def test_set_option_invalid_kwargs_key(self):
185+
self.assertRaises(ValueError, self.cf.set_option, 'a.b', 2,
186+
silenadf=2)
187+
188+
def test_set_option_invalid_kwargs_value_type(self):
189+
self.assertRaises(TypeError, self.cf.set_option, 'a.b', 2,
190+
silent=2)
191+
192+
def test_set_option_invalid_single_argument_type(self):
193+
self.assertRaises(AssertionError, self.cf.set_option, 2)
194+
195+
def test_set_option_multiple(self):
196+
self.cf.register_option('a', 1, 'doc')
197+
self.cf.register_option('b.c', 'hullo', 'doc2')
198+
self.cf.register_option('b.b', None, 'doc2')
199+
200+
self.assertEqual(self.cf.get_option('a'), 1)
201+
self.assertEqual(self.cf.get_option('b.c'), 'hullo')
202+
self.assertTrue(self.cf.get_option('b.b') is None)
203+
204+
self.cf.set_option('a', '2', 'b.c', None, 'b.b', 10.0)
205+
206+
self.assertEqual(self.cf.get_option('a'), '2')
207+
self.assertTrue(self.cf.get_option('b.c') is None)
208+
self.assertEqual(self.cf.get_option('b.b'), 10.0)
209+
172210
def test_validation(self):
173211
self.cf.register_option('a', 1, 'doc', validator=self.cf.is_int)
174212
self.cf.register_option('b.c', 'hullo', 'doc2',

0 commit comments

Comments
 (0)