Creating an optional datetime parameter using Param?

BTW, here’s how I’d translate the pydantic home page example into Param:

import param

class User(param.Parameterized):
    id = param.Integer()
    name = param.String()
    signup_ts = param.Date(None)
    friends = param.List([], item_type=int)

from datetime import datetime    
external_data = {
    'id': 123,
    'name': 'John Doe',
    'signup_ts': datetime.strptime('2019-06-01 12:22', '%Y-%m-%d %H:%M'),
    'friends': [1, 2, 3],
}

user = User(**external_data)
print(user.id)
#> 123

print(repr(user.signup_ts))
#> datetime.datetime(2019, 6, 1, 12, 22)

print(user.friends)
#> [1, 2, 3]

print(user.param.values())
"""
{
    'friends': [1, 2, 3],
    'id': 123,
    'name': 'John Doe',
    'signup_ts': datetime.datetime(2019, 6, 1, 12, 22)
}
"""

This is essentially a direct translation, with some very specific differences:

  1. Param won’t coerce any foreign type into the required type. So if id is an integer field, Param will raise an exception (by design) for id='123', while Pydantic accepts that and coerces the string to an int.
  2. Same goes for items in lists; Param will raise “TypeError: List parameter ‘friends’ items must be instances of type <class ‘int’>” if you try supplying friends= [1, 2, '3'], while Pydantic will coerce it.
  3. A param.Date Parameter will only accept date or datetimes, not strings. Given how painful it is to construct date and datetime objects, I’d be happy to support the specific case of accepting string specifications for Date and CalendarDate constructors, where the string is unlikely to be an error as it would be for the int or list of int cases (as proposed in https://github.com/holoviz/param/issues/580#issuecomment-995094791). In the meantime, it’s necessary for the user to construct the date/datetime object, not Param.
  4. name is the one Parameter that Parameterized objects always have, and it’s also the only one that has special semantics in Param: If the name is not set on an instance or in its constructor, it has a name autogenerated for it from the class name. The intention of this mechanism is for each object to have some relatively unique name to distinguish it when exploring collections of objects, though that’s not necessarily always useful. In any case, here, if we want it to have the value John Doe as in the Pydantic example, we have to provide that name explicitly on the instance as above. The original Pydantic example doesn’t make a whole lot of sense for name anyway, as it would be a recipe for errors for something like a name to inherit a concrete value like John Doe from the base class.

I’d be happy to have this example in the docs or the Comparisons page to clarify how Param and Pydantic relate; PRs welcome!

1 Like