holoviz / holoviz/param

Default value of `allow_None` for Selectors

Open
#695 2 comments 0 reactions 0 assignees View on GitHub
type-bug
Dominant language
Python
Stars
521
Forks
86
Avg merge
1d 13h
Merged PRs (30d)
35

Description

The `Selector` Parameter is instantiated with `allow_None=None`. All of its descendants inherit this.

```python
>>> import param
>>> print(param.concrete_descendents(param.Selector))
{'Selector': param.Selector,
'ObjectSelector': param.ObjectSelector,
'FileSelector': param.FileSelector,
'ListSelector': param.ListSelector,
'MultiFileSelector': param.MultiFileSelector}
```

It is the only case of `allow_None` set to `None`, otherwise it's set to either `True` or `False`.

Functionally, setting it to `False` by default would I think lead to the exact same behaviors. So I wonder why it's `None` (it's pretty old code that's inherited from when it was in `ObjectSelector`)? That's maybe the source of this rather dry issue opened by Chris a while ago (https://github.com/holoviz/param/issues/106) ?

---

I find the semantics of `allow_None` for Selectors a bit confusing.

First, it's possible to fool Param (or yourself?), by either not allowing `None` by including it in the list of allowed objects, or by not allowing it but by setting `check_on_set` to `False`.

```python
import param

class P(param.Parameterized):
s = param.Selector(objects=[1, 2, None], allow_None=False)
t = param.Selector(objects=[1, 2], allow_None=False, check_on_set=False)

p = P()

p.s = None

p.t = None

print(p.param.s.allow_None, p.param.t.allow_None)
# False False
```

I find strange that it's possible to have a default value of `None`, set the parameter to another valid value, and not be able to set it back to `None`.

```python
import param

class P(param.Parameterized):
s = param.ListSelector(default=None, objects=[1, 2])

p = P()

assert p.s is None

p.s = [1]

p.s = None
```

```
ValueError Traceback (most recent call last)
Cell In[73], line 12
8 assert p.s is None
10 p.s = [1]
---> 12 p.s = None

File ~/dev/param_main/param/parameterized.py:375, in instance_descriptor.._f(self, obj, val)
373 instance_param.__set__(obj, val)
374 return
--> 375 return f(self, obj, val)

File ~/dev/param_main/param/parameterized.py:1213, in Parameter.__set__(self, obj, val)
1210 if hasattr(self, 'set_hook'):
1211 val = self.set_hook(obj,val)
-> 1213 self._validate(val)
1215 _old = NotImplemented
1216 # obj can be None if __set__ is called for a Parameterized class

File ~/dev/param_main/param/__init__.py:1918, in ListSelector._validate(self, val)
1916 return
1917 if not isinstance(val, list):
-> 1918 raise ValueError("ListSelector parameter %r only takes list "
1919 "types, not %r." % (self.name, val))
1920 for o in val:
1921 super(ListSelector, self)._validate(o)

ValueError: ListSelector parameter 's' only takes list types, not None.
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.