Skip to content

Commit ee5cb34

Browse files
committed
Accept NumPy scalars in integer and string properties
1 parent 38374ac commit ee5cb34

4 files changed

Lines changed: 31 additions & 9 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
1717
- Fix Plotly Express mutating lists passed to the `x` or `y` arguments in wide mode [[#5727](https://github.com/plotly/plotly.py/pull/5727)], with thanks to @cpruijsen for the contribution!
1818
- Fix `px.sunburst`, `px.treemap` and `px.icicle` listing sectors in a different order on every run when `path` is used with a Polars DataFrame; sectors now follow their order of first appearance for all dataframe backends [[#5766](https://github.com/plotly/plotly.py/pull/5766)], with thanks to @Irahan2 for the contribution!
1919
- Fix `mpl_to_plotly` conversion of matplotlib contour lines and line collections: close contour rings ending with `Z` codes, support dash styles, convert date x-axes, separate disjoint subpaths with `None` separators, hide line collection traces from the legend by default, and group consecutive same-style lines into single traces [[#5770](https://github.com/plotly/plotly.py/pull/5770)], with thanks to @robertoffmoura for the contribution!
20+
- Fix graph object properties rejecting NumPy scalars: integer properties (such as `nticks`, `nbinsx` and `updatemenus[].active`) now accept NumPy integers, and string properties (such as `name` and `text`) now accept NumPy numbers, as they already did Python `int` and `float` values [[#5828](https://github.com/plotly/plotly.py/pull/5828)], with thanks to @RaphaelFakhri for the contribution!
2021

2122
## [7.1.0] - 2026-09-15
2223

‎_plotly_utils/basevalidators.py‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -918,7 +918,9 @@ def validate_coerce(self, v):
918918
elif self.array_ok and is_simple_array(v):
919919
# Check integer type
920920
invalid_els = [
921-
e for e in v if not isinstance(e, int) and e not in self.extras
921+
e
922+
for e in v
923+
if not isinstance(e, numbers.Integral) and e not in self.extras
922924
]
923925

924926
if invalid_els:
@@ -929,7 +931,10 @@ def validate_coerce(self, v):
929931
invalid_els = [
930932
e
931933
for e in v
932-
if not (isinstance(e, int) and self.min_val <= e <= self.max_val)
934+
if not (
935+
isinstance(e, numbers.Integral)
936+
and self.min_val <= e <= self.max_val
937+
)
933938
and e not in self.extras
934939
]
935940

@@ -939,7 +944,7 @@ def validate_coerce(self, v):
939944
v = to_scalar_or_list(v)
940945
else:
941946
# Check int
942-
if not isinstance(v, int):
947+
if not isinstance(v, numbers.Integral):
943948
# don't let int() cast strings to ints
944949
self.raise_invalid_val(v)
945950

@@ -1100,7 +1105,7 @@ def validate_coerce(self, v):
11001105
else:
11011106
if isinstance(v, str):
11021107
pass
1103-
elif isinstance(v, (int, float)):
1108+
elif isinstance(v, numbers.Number):
11041109
# Convert value to a string
11051110
v = str(v)
11061111
else:

‎tests/test_plotly_utils/validators/test_integer_validator.py‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ def validator_extras_aok():
4646

4747

4848
# Acceptance
49-
@pytest.mark.parametrize("val", [1, -19, 0, -1234])
49+
@pytest.mark.parametrize(
50+
"val", [1, -19, 0, -1234, np.int64(5), np.int32(-3), np.uint8(7)]
51+
)
5052
def test_acceptance(val, validator):
5153
assert validator.validate_coerce(val) == val
5254

@@ -64,7 +66,7 @@ def test_rejection_by_value(val, validator):
6466

6567
# With min/max
6668
# min == -1 and max == 2
67-
@pytest.mark.parametrize("val", [0, 1, -1, 2])
69+
@pytest.mark.parametrize("val", [0, 1, -1, 2, np.int64(2)])
6870
def test_acceptance_min_max(val, validator_min_max):
6971
assert validator_min_max.validate_coerce(val) == approx(val)
7072

@@ -91,7 +93,7 @@ def test_rejection_extras(val, validator_extras):
9193

9294

9395
@pytest.mark.parametrize(
94-
"val", [-1.01, -10, 2.1, 3, np.iinfo(int).max, np.iinfo(int).min]
96+
"val", [-1.01, -10, 2.1, 3, np.int64(3), np.iinfo(int).max, np.iinfo(int).min]
9597
)
9698
def test_rejection_min_max(val, validator_min_max):
9799
with pytest.raises(ValueError) as validation_failure:
@@ -140,7 +142,10 @@ def test_acceptance_aok_scalars(val, validator_aok):
140142
assert validator_aok.validate_coerce(val) == val
141143

142144

143-
@pytest.mark.parametrize("val", [[1, 0], [1], [-2, 1, 8], np.array([3, 2, -1, 5])])
145+
@pytest.mark.parametrize(
146+
"val",
147+
[[1, 0], [1], [-2, 1, 8], [np.int64(3), np.int32(-1)], np.array([3, 2, -1, 5])],
148+
)
144149
def test_acceptance_aok_list(val, validator_aok):
145150
assert np.array_equal(validator_aok.validate_coerce(val), val)
146151

‎tests/test_plotly_utils/validators/test_string_validator.py‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,18 @@ def validator_no_blanks_aok():
5656
# Not strict
5757
# Acceptance
5858
@pytest.mark.parametrize(
59-
"val", ["bar", 234, np_nan(), "HELLO!!!", "world!@#$%^&*()", "", "\u03bc"]
59+
"val",
60+
[
61+
"bar",
62+
234,
63+
np_nan(),
64+
np.int64(234),
65+
np.float32(1.5),
66+
"HELLO!!!",
67+
"world!@#$%^&*()",
68+
"",
69+
"\u03bc",
70+
],
6071
)
6172
def test_acceptance(val, validator):
6273
expected = str(val) if not isinstance(val, str) else val

0 commit comments

Comments
 (0)