Skip to content

Commit f9f95c0

Browse files
Adam-KlaumWillAyd
authored andcommitted
ENH: Validation to only allow positive integers for options (#27382)
1 parent 0e7ed3d commit f9f95c0

File tree

4 files changed

+50
-11
lines changed

4 files changed

+50
-11
lines changed

doc/source/whatsnew/v1.0.0.rst

+6
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,12 @@ ExtensionArray
195195
-
196196
-
197197

198+
199+
Other
200+
^^^^^
201+
- Trying to set the ``display.precision``, ``display.max_rows`` or ``display.max_columns`` using :meth:`set_option` to anything but a ``None`` or a positive int will raise a ``ValueError`` (:issue:`23348`)
202+
203+
198204
.. _whatsnew_1000.contributors:
199205

200206
Contributors

pandas/_config/config.py

+27
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,7 @@ def is_instance_factory(_type):
787787
ValueError if x is not an instance of `_type`
788788
789789
"""
790+
790791
if isinstance(_type, (tuple, list)):
791792
_type = tuple(_type)
792793
type_repr = "|".join(map(str, _type))
@@ -820,6 +821,32 @@ def inner(x):
820821
return inner
821822

822823

824+
def is_nonnegative_int(value):
825+
"""
826+
Verify that value is None or a positive int.
827+
828+
Parameters
829+
----------
830+
value : None or int
831+
The `value` to be checked.
832+
833+
Raises
834+
------
835+
ValueError
836+
When the value is not None or is a negative integer
837+
"""
838+
839+
if value is None:
840+
return
841+
842+
elif isinstance(value, int):
843+
if value >= 0:
844+
return
845+
846+
msg = "Value must be a nonnegative integer or None"
847+
raise ValueError(msg)
848+
849+
823850
# common type validators, for convenience
824851
# usage: register_option(... , validator = is_int)
825852
is_int = is_type_factory(int)

pandas/core/config_init.py

+4-11
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
is_callable,
1818
is_instance_factory,
1919
is_int,
20+
is_nonnegative_int,
2021
is_one_of_factory,
2122
is_text,
2223
)
@@ -319,7 +320,7 @@ def is_terminal():
319320

320321

321322
with cf.config_prefix("display"):
322-
cf.register_option("precision", 6, pc_precision_doc, validator=is_int)
323+
cf.register_option("precision", 6, pc_precision_doc, validator=is_nonnegative_int)
323324
cf.register_option(
324325
"float_format",
325326
None,
@@ -333,12 +334,7 @@ def is_terminal():
333334
pc_max_info_rows_doc,
334335
validator=is_instance_factory((int, type(None))),
335336
)
336-
cf.register_option(
337-
"max_rows",
338-
60,
339-
pc_max_rows_doc,
340-
validator=is_instance_factory([type(None), int]),
341-
)
337+
cf.register_option("max_rows", 60, pc_max_rows_doc, validator=is_nonnegative_int)
342338
cf.register_option(
343339
"min_rows",
344340
10,
@@ -352,10 +348,7 @@ def is_terminal():
352348
else:
353349
max_cols = 20 # cannot determine optimal number of columns
354350
cf.register_option(
355-
"max_columns",
356-
max_cols,
357-
pc_max_cols_doc,
358-
validator=is_instance_factory([type(None), int]),
351+
"max_columns", max_cols, pc_max_cols_doc, validator=is_nonnegative_int
359352
)
360353
cf.register_option(
361354
"large_repr",

pandas/tests/config/test_config.py

+13
Original file line numberDiff line numberDiff line change
@@ -208,20 +208,33 @@ def test_set_option_multiple(self):
208208

209209
def test_validation(self):
210210
self.cf.register_option("a", 1, "doc", validator=self.cf.is_int)
211+
self.cf.register_option("d", 1, "doc", validator=self.cf.is_nonnegative_int)
211212
self.cf.register_option("b.c", "hullo", "doc2", validator=self.cf.is_text)
213+
212214
msg = "Value must have type '<class 'int'>'"
213215
with pytest.raises(ValueError, match=msg):
214216
self.cf.register_option("a.b.c.d2", "NO", "doc", validator=self.cf.is_int)
215217

216218
self.cf.set_option("a", 2) # int is_int
217219
self.cf.set_option("b.c", "wurld") # str is_str
220+
self.cf.set_option("d", 2)
218221

219222
# None not is_int
220223
with pytest.raises(ValueError, match=msg):
221224
self.cf.set_option("a", None)
222225
with pytest.raises(ValueError, match=msg):
223226
self.cf.set_option("a", "ab")
224227

228+
msg = "Value must be a nonnegative integer or None"
229+
with pytest.raises(ValueError, match=msg):
230+
self.cf.register_option(
231+
"a.b.c.d3", "NO", "doc", validator=self.cf.is_nonnegative_int
232+
)
233+
with pytest.raises(ValueError, match=msg):
234+
self.cf.register_option(
235+
"a.b.c.d3", -2, "doc", validator=self.cf.is_nonnegative_int
236+
)
237+
225238
msg = r"Value must be an instance of <class 'str'>\|<class 'bytes'>"
226239
with pytest.raises(ValueError, match=msg):
227240
self.cf.set_option("b.c", 1)

0 commit comments

Comments
 (0)