param 2.4.0rc0__tar.gz → 2.4.0rc2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. {param-2.4.0rc0 → param-2.4.0rc2}/PKG-INFO +1 -1
  2. {param-2.4.0rc0 → param-2.4.0rc2}/param/_utils.py +4 -3
  3. {param-2.4.0rc0 → param-2.4.0rc2}/param/_version.py +2 -2
  4. {param-2.4.0rc0 → param-2.4.0rc2}/param/parameterized.py +4 -4
  5. {param-2.4.0rc0 → param-2.4.0rc2}/param/parameters.py +240 -37
  6. param-2.4.0rc2/tests/assert_types.py +426 -0
  7. param-2.4.0rc2/tests/pyrightconfig-bare.json +1 -0
  8. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testpickle.py +2 -1
  9. {param-2.4.0rc0 → param-2.4.0rc2}/.gitignore +0 -0
  10. {param-2.4.0rc0 → param-2.4.0rc2}/LICENSE.txt +0 -0
  11. {param-2.4.0rc0 → param-2.4.0rc2}/README.md +0 -0
  12. {param-2.4.0rc0 → param-2.4.0rc2}/numbergen/__init__.py +0 -0
  13. {param-2.4.0rc0 → param-2.4.0rc2}/param/__init__.py +0 -0
  14. {param-2.4.0rc0 → param-2.4.0rc2}/param/depends.py +0 -0
  15. {param-2.4.0rc0 → param-2.4.0rc2}/param/display.py +0 -0
  16. {param-2.4.0rc0 → param-2.4.0rc2}/param/ipython.py +0 -0
  17. {param-2.4.0rc0 → param-2.4.0rc2}/param/py.typed +0 -0
  18. {param-2.4.0rc0 → param-2.4.0rc2}/param/reactive.py +0 -0
  19. {param-2.4.0rc0 → param-2.4.0rc2}/param/serializer.py +0 -0
  20. {param-2.4.0rc0 → param-2.4.0rc2}/param/version.py +0 -0
  21. {param-2.4.0rc0 → param-2.4.0rc2}/pyproject.toml +0 -0
  22. {param-2.4.0rc0 → param-2.4.0rc2}/tests/__init__.py +0 -0
  23. {param-2.4.0rc0 → param-2.4.0rc2}/tests/conftest.py +0 -0
  24. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testaddparameter.py +0 -0
  25. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testbind.py +0 -0
  26. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testbooleanparam.py +0 -0
  27. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testbytesparam.py +0 -0
  28. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testcalendardateparam.py +0 -0
  29. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testcalendardaterangeparam.py +0 -0
  30. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testcallable.py +0 -0
  31. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testclassselector.py +0 -0
  32. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testcolorparameter.py +0 -0
  33. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testcomparator.py +0 -0
  34. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testcompositeparams.py +0 -0
  35. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testcustomparam.py +0 -0
  36. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testdateparam.py +0 -0
  37. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testdaterangeparam.py +0 -0
  38. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testdefaultfactory.py +0 -0
  39. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testdefaults.py +0 -0
  40. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testdeprecations.py +0 -0
  41. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testdynamicparams.py +0 -0
  42. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testfiledeserialization.py +0 -0
  43. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testfileselector.py +0 -0
  44. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testimports.py +0 -0
  45. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testipythonmagic.py +0 -0
  46. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testjsonserialization.py +0 -0
  47. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testlist.py +0 -0
  48. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testlistselector.py +0 -0
  49. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testmultifileselector.py +0 -0
  50. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testnumbergen.py +0 -0
  51. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testnumberparameter.py +0 -0
  52. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testnumpy.py +0 -0
  53. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testobjectselector.py +0 -0
  54. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testpandas.py +0 -0
  55. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testparamdepends.py +0 -0
  56. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testparameter.py +0 -0
  57. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testparameterizedobject.py +0 -0
  58. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testparameterizedrepr.py +0 -0
  59. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testparamoutput.py +0 -0
  60. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testparamunion.py +0 -0
  61. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testpathparam.py +0 -0
  62. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testrangeparameter.py +0 -0
  63. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testreactive.py +0 -0
  64. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testrefs.py +0 -0
  65. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testreprhtml.py +0 -0
  66. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testselector.py +0 -0
  67. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testsignatures.py +0 -0
  68. {param-2.4.0rc0 → param-2.4.0rc2}/tests/teststringparam.py +0 -0
  69. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testtimedependent.py +0 -0
  70. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testtupleparam.py +0 -0
  71. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testutils.py +0 -0
  72. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testversion.py +0 -0
  73. {param-2.4.0rc0 → param-2.4.0rc2}/tests/testwatch.py +0 -0
  74. {param-2.4.0rc0 → param-2.4.0rc2}/tests/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: param
3
- Version: 2.4.0rc0
3
+ Version: 2.4.0rc2
4
4
  Summary: Declarative parameters for robust Python classes and a rich API for reactive programming
5
5
  Project-URL: Homepage, https://param.holoviz.org/
6
6
  Project-URL: Tracker, https://github.com/holoviz/param/issues
@@ -19,6 +19,7 @@ if t.TYPE_CHECKING:
19
19
 
20
20
  _P = t.ParamSpec("_P")
21
21
  _R = t.TypeVar("_R")
22
+ _T = t.TypeVar("_T")
22
23
  _CallableT = t.TypeVar("_CallableT", bound=abc.Callable)
23
24
 
24
25
  DEFAULT_SIGNATURE = inspect.Signature([
@@ -443,7 +444,7 @@ def _is_abstract(class_: type) -> bool:
443
444
  return bool(getattr(class_, "abstract", False))
444
445
 
445
446
 
446
- def descendents(class_: type, concrete: bool = False) -> list[type]:
447
+ def descendents(class_: type[_T], concrete: bool = False) -> list[type[_T]]:
447
448
  """
448
449
  Return a list of all descendent classes of a given class.
449
450
 
@@ -482,7 +483,7 @@ def descendents(class_: type, concrete: bool = False) -> list[type]:
482
483
  if not isinstance(class_, type):
483
484
  raise TypeError(f"descendents expected a class object, not {type(class_).__name__}")
484
485
  q = [class_]
485
- out: list[type] = []
486
+ out: list[type[_T]] = []
486
487
  while len(q):
487
488
  x = q.pop(0)
488
489
  out.insert(0, x)
@@ -499,7 +500,7 @@ def descendents(class_: type, concrete: bool = False) -> list[type]:
499
500
 
500
501
 
501
502
  # Could be a method of ClassSelector.
502
- def concrete_descendents(parentclass: type) -> dict[str, type]:
503
+ def concrete_descendents(parentclass: type[_T]) -> dict[str, type[_T]]:
503
504
  """
504
505
  Return a dictionary containing all subclasses of the specified
505
506
  parentclass, including the parentclass (prefer :func:`descendents`).
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '2.4.0rc0'
22
- __version_tuple__ = version_tuple = (2, 4, 0, 'rc0')
21
+ __version__ = version = '2.4.0rc2'
22
+ __version_tuple__ = version_tuple = (2, 4, 0, 'rc2')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -1944,7 +1944,7 @@ class Parameter(_ParameterBase, t.Generic[_T]):
1944
1944
  return result
1945
1945
 
1946
1946
  @instance_descriptor
1947
- def __set__(self, obj: Parameterized, val: _T):
1947
+ def __set__(self, obj: Parameterized | None, val: _T):
1948
1948
  """
1949
1949
  Set the value for this Parameter.
1950
1950
 
@@ -2253,9 +2253,9 @@ class String(Parameter[_T]):
2253
2253
  self._validate(self.default)
2254
2254
 
2255
2255
  def _validate_regex(self, val: t.Any, regex: str | re.Pattern[str] | None):
2256
- if (val is None and self.allow_None):
2256
+ if val is None or regex is None:
2257
2257
  return
2258
- if regex is not None and re.match(regex, val) is None:
2258
+ if re.fullmatch(regex, val) is None:
2259
2259
  raise ValueError(
2260
2260
  f'{_validate_error_prefix(self)} value {val!r} does not '
2261
2261
  f'match regex {regex!r}.'
@@ -2731,7 +2731,7 @@ class Parameters:
2731
2731
  except Skip:
2732
2732
  value = Undefined
2733
2733
  if is_async and pobj.name:
2734
- async_executor(partial(self_._async_ref, pobj.name, value))
2734
+ async_executor(partial(self_._async_ref, pobj.name, t.cast("t.Awaitable[t.Any]", value)))
2735
2735
  value = None
2736
2736
  return ref, deps, value, is_async
2737
2737
 
@@ -19,6 +19,7 @@ from __future__ import annotations
19
19
 
20
20
  import copy
21
21
  import datetime as dt
22
+ import enum
22
23
  import glob
23
24
  import inspect
24
25
  import numbers
@@ -605,17 +606,17 @@ class Dynamic(Parameter[_T]):
605
606
  Call the superclass's __init__ and set instantiate=True if the
606
607
  default is dynamic.
607
608
  """
608
- super().__init__(default=default, allow_None=allow_None, **params)
609
+ super().__init__(default=default, allow_None=allow_None, **params) # ty: ignore[no-matching-overload]
609
610
 
610
611
  if callable(self.default):
611
612
  self._set_instantiate(True)
612
613
  self._initialize_generator(self.default)
613
614
 
614
- def _initialize_generator(self, gen, obj=None):
615
+ def _initialize_generator(self, gen, obj: Parameterized | None = None):
615
616
  """Add 'last time' and 'last value' attributes to the generator."""
616
617
  # Could use a dictionary to hold these things.
617
618
  if obj is not None and hasattr(obj, "_Dynamic_time_fn"):
618
- gen._Dynamic_time_fn = obj._Dynamic_time_fn
619
+ gen._Dynamic_time_fn = obj._Dynamic_time_fn # type: ignore[attribute-access]
619
620
 
620
621
  gen._Dynamic_last = None
621
622
  # Would have usede None for this, but can't compare a fixedpoint
@@ -641,7 +642,7 @@ class Dynamic(Parameter[_T]):
641
642
  return t.cast("_T", self._produce_value(gen))
642
643
 
643
644
  @instance_descriptor
644
- def __set__(self, obj: Parameterized, val: _T):
645
+ def __set__(self, obj: Parameterized | None, val: _T):
645
646
  """
646
647
  Call the superclass's set and keep this parameter's
647
648
  instantiate value up to date (dynamic parameters
@@ -652,8 +653,10 @@ class Dynamic(Parameter[_T]):
652
653
  super().__set__(obj, val)
653
654
 
654
655
  dynamic = callable(val)
655
- if dynamic: self._initialize_generator(val,obj)
656
- if obj is None: self._set_instantiate(dynamic)
656
+ if dynamic:
657
+ self._initialize_generator(val, obj)
658
+ if obj is None:
659
+ self._set_instantiate(dynamic)
657
660
 
658
661
  def _produce_value(self, gen, force: bool = False):
659
662
  """
@@ -1154,7 +1157,7 @@ class Magnitude(Number[_T]):
1154
1157
  allow_None: bool = t.cast("bool", Undefined), # pyrefly: ignore[bad-argument-type]
1155
1158
  **kwargs: Unpack[_NumberInitKwargs]
1156
1159
  ) -> None:
1157
- super().__init__( # type: ignore[misc, call-overload]
1160
+ super().__init__( # type: ignore[misc, call-overload]
1158
1161
  default=default, allow_None=allow_None, **kwargs # type: ignore[arg-type]
1159
1162
  )
1160
1163
 
@@ -1307,7 +1310,7 @@ class CalendarDate(Number[_T]):
1307
1310
  allow_None: bool = t.cast("bool", Undefined), # pyrefly: ignore[bad-argument-type]
1308
1311
  **kwargs: Unpack[_CalendarDateInitKwargs]
1309
1312
  ) -> None:
1310
- super().__init__( # type: ignore[misc, call-overload]
1313
+ super().__init__( # type: ignore[misc, call-overload] # ty: ignore[no-matching-overload]
1311
1314
  default=default, allow_None=allow_None, **kwargs # type: ignore[arg-type]
1312
1315
  )
1313
1316
 
@@ -1606,7 +1609,7 @@ class Tuple(Parameter[_T]):
1606
1609
  )
1607
1610
 
1608
1611
  def _validate_length(self, val, length):
1609
- if val is None and self.allow_None:
1612
+ if val is None:
1610
1613
  return
1611
1614
 
1612
1615
  if not len(val) == length:
@@ -1898,16 +1901,17 @@ class Range(NumericTuple[_T]):
1898
1901
  )
1899
1902
 
1900
1903
  def _validate_bounds(self, val, bounds, inclusive_bounds, kind):
1901
- if bounds is not None:
1902
- for pos, v in zip(['lower', 'upper'], bounds):
1903
- if v is None:
1904
- continue
1905
- self._validate_bound_type(v, pos, kind)
1906
- if kind == 'softbound':
1904
+ if bounds is None:
1907
1905
  return
1908
1906
 
1909
- if bounds is None or (val is None and self.allow_None):
1907
+ for pos, v in zip(['lower', 'upper'], bounds):
1908
+ if v is None:
1909
+ continue
1910
+ self._validate_bound_type(v, pos, kind)
1911
+
1912
+ if val is None or kind == 'softbound':
1910
1913
  return
1914
+
1911
1915
  vmin, vmax = bounds
1912
1916
  incmin, incmax = inclusive_bounds
1913
1917
  for bound, v in zip(['lower', 'upper'], val):
@@ -1984,7 +1988,7 @@ class DateRange(Range[_T]):
1984
1988
  allow_None: bool = t.cast("bool", Undefined), # pyrefly: ignore[bad-argument-type]
1985
1989
  **kwargs: Unpack[_DateInitKwargs]
1986
1990
  ) -> None:
1987
- super().__init__(default=default, allow_None=allow_None, **kwargs) # type: ignore[misc, call-overload]
1991
+ super().__init__(default=default, allow_None=allow_None, **kwargs) # type: ignore[misc, call-overload, ty:invalid-argument-type]
1988
1992
 
1989
1993
  def _validate_bound_type(self, value, position, kind):
1990
1994
  if not isinstance(value, _dt_types):
@@ -2107,7 +2111,7 @@ class CalendarDateRange(Range[_T]):
2107
2111
  allow_None: bool = t.cast("bool", Undefined), # pyrefly: ignore[bad-argument-type]
2108
2112
  **kwargs: Unpack[_CalendarDateInitKwargs]
2109
2113
  ) -> None:
2110
- super().__init__(default=default, allow_None=allow_None, **kwargs) # type: ignore[misc, call-overload]
2114
+ super().__init__(default=default, allow_None=allow_None, **kwargs) # type: ignore[misc, call-overload] # ty: ignore[invalid-argument-type]
2111
2115
 
2112
2116
  def _validate_value(self, value, allow_None):
2113
2117
  if allow_None and value is None:
@@ -2216,11 +2220,54 @@ class Callable(Parameter[_T]):
2216
2220
  self._validate_value(val, self.allow_None)
2217
2221
 
2218
2222
 
2219
- class Action(Callable):
2223
+ class Action(Callable[_T]):
2220
2224
  """
2221
2225
  A user-provided function that can be invoked like a class or object method using ().
2222
2226
  In a GUI, this might be mapped to a button, but it can be invoked directly as well.
2223
2227
  """
2228
+
2229
+ if t.TYPE_CHECKING:
2230
+
2231
+ @t.overload
2232
+ def __init__(
2233
+ self: Action[t.Callable[[], t.Any]],
2234
+ default: t.Callable[[], t.Any] = lambda: None,
2235
+ *,
2236
+ allow_None: t.Literal[False] = False,
2237
+ doc: str | None = None,
2238
+ label: str | None = None,
2239
+ precedence: float | None = None,
2240
+ instantiate: bool = False,
2241
+ constant: bool = False,
2242
+ readonly: bool = False,
2243
+ pickle_default_value: bool = True,
2244
+ per_instance: bool = True,
2245
+ allow_refs: bool = False,
2246
+ nested_refs: bool = False,
2247
+ default_factory: t.Callable[[], t.Any] | None = None,
2248
+ metadata: dict[str, t.Any] | None = None,
2249
+ ) -> None:
2250
+ ...
2251
+
2252
+ @t.overload
2253
+ def __init__(
2254
+ self: Action[t.Callable[[], t.Any] | None],
2255
+ default: None = None,
2256
+ *,
2257
+ allow_None: t.Literal[True] = True,
2258
+ **params: Unpack[_ParameterKwargs]
2259
+ ) -> None:
2260
+ ...
2261
+
2262
+ def __init__(self,
2263
+ default: t.Callable[[], t.Any] | None = t.cast("t.Callable[[], t.Any] | None", Undefined), # pyrefly: ignore[bad-argument-type]
2264
+ *,
2265
+ allow_None: bool = t.cast("bool", Undefined), # pyrefly: ignore[bad-argument-type]
2266
+ **params: Unpack[_ParameterKwargs]
2267
+ ) -> None:
2268
+ super().__init__(default=default, **params) # type: ignore[misc] # pyrefly: ignore[bad-argument-type]
2269
+ self._validate(self.default)
2270
+
2224
2271
  # Currently same implementation as Callable, but kept separate to allow different handling in GUIs
2225
2272
 
2226
2273
  #-----------------------------------------------------------------------------
@@ -2829,14 +2876,14 @@ class ListSelector(Selector):
2829
2876
  self.objects.append(o)
2830
2877
 
2831
2878
  def _validate(self, val):
2832
- if (val is None and self.allow_None):
2879
+ if val is None and self.allow_None:
2833
2880
  return
2834
2881
  self._validate_type(val)
2835
2882
 
2836
2883
  if self.check_on_set:
2837
2884
  self._validate_value(val)
2838
2885
  else:
2839
- for v in val:
2886
+ for v in val: # pyright: ignore[reportOptionalIterable]
2840
2887
  self._ensure_value_is_in_objects(v)
2841
2888
 
2842
2889
  def _validate_type(self, val):
@@ -2901,6 +2948,14 @@ class MultiFileSelector(ListSelector):
2901
2948
  return _abbreviate_paths(self.path, super().get_range())
2902
2949
 
2903
2950
 
2951
+ class NoNoneType(enum.Enum):
2952
+ NO_NONE = enum.auto()
2953
+
2954
+
2955
+ NoNone = NoNoneType.NO_NONE
2956
+
2957
+
2958
+
2904
2959
  class ClassSelector(SelectorBase[_T]):
2905
2960
  """
2906
2961
  Parameter allowing selection of either a subclass or an instance of a class
@@ -2960,6 +3015,18 @@ class ClassSelector(SelectorBase[_T]):
2960
3015
  ) -> None:
2961
3016
  ...
2962
3017
 
3018
+ @t.overload
3019
+ def __init__(
3020
+ self: ClassSelector[CT],
3021
+ *,
3022
+ default: CT | None = None,
3023
+ class_: type[CT],
3024
+ is_instance: t.Literal[True] = True,
3025
+ allow_None: NoNoneType,
3026
+ **kwargs: Unpack[_ParameterKwargs]
3027
+ ) -> None:
3028
+ ...
3029
+
2963
3030
  @t.overload
2964
3031
  def __init__(
2965
3032
  self: ClassSelector[CT | None],
@@ -3006,6 +3073,18 @@ class ClassSelector(SelectorBase[_T]):
3006
3073
  ) -> None:
3007
3074
  ...
3008
3075
 
3076
+ @t.overload
3077
+ def __init__(
3078
+ self: ClassSelector[type[CT]],
3079
+ *,
3080
+ default: type[CT] | None = None,
3081
+ class_: type[CT],
3082
+ is_instance: t.Literal[False],
3083
+ allow_None: NoNoneType,
3084
+ **kwargs: Unpack[_ParameterKwargs]
3085
+ ) -> None:
3086
+ ...
3087
+
3009
3088
  @t.overload
3010
3089
  def __init__(
3011
3090
  self: ClassSelector[type[CT] | None],
@@ -3046,9 +3125,10 @@ class ClassSelector(SelectorBase[_T]):
3046
3125
  class_: type | tuple[type, ...] = t.cast("type | tuple[type, ...]", Undefined), # pyrefly: ignore[bad-argument-type]
3047
3126
  default: t.Any | None = Undefined,
3048
3127
  is_instance: bool = t.cast("bool", Undefined), # pyrefly: ignore[bad-argument-type]
3049
- allow_None: bool = t.cast("bool", Undefined), # pyrefly: ignore[bad-argument-type]
3128
+ allow_None: bool | NoNoneType = t.cast("bool", Undefined), # pyrefly: ignore[bad-argument-type]
3050
3129
  **params: Unpack[_ParameterKwargs]
3051
3130
  ) -> None:
3131
+ allow_None = t.cast("bool", Undefined if allow_None is NoNone else allow_None)
3052
3132
  object.__setattr__(self, 'class_', class_)
3053
3133
  object.__setattr__(self, 'is_instance', is_instance) # type: ignore
3054
3134
  super().__init__( # type: ignore[misc, call-overload]
@@ -3063,7 +3143,9 @@ class ClassSelector(SelectorBase[_T]):
3063
3143
  def _validate_class_(self, val: t.Any, class_: type | tuple[type, ...], is_instance: bool):
3064
3144
  if (val is None and self.allow_None):
3065
3145
  return
3066
- if (is_instance and isinstance(val, class_)) or (not is_instance and issubclass(val, class_)):
3146
+ if (is_instance and isinstance(val, class_)) or (
3147
+ not is_instance and isinstance(val, type) and issubclass(val, class_)
3148
+ ):
3067
3149
  return
3068
3150
 
3069
3151
  if isinstance(class_, tuple):
@@ -3152,7 +3234,7 @@ class Dict(ClassSelector[_T]):
3152
3234
  allow_None: bool = t.cast("bool", Undefined), # pyrefly: ignore[bad-argument-type]
3153
3235
  **params: Unpack[_ClassSelectorKwargs]
3154
3236
  ) -> None:
3155
- super().__init__( # type: ignore[misc, call-overload]
3237
+ super().__init__( # type: ignore[misc, call-overload] # ty: ignore[no-matching-overload]
3156
3238
  default=default, class_=dict, allow_None=allow_None, **params # type: ignore[arg-type]
3157
3239
  )
3158
3240
 
@@ -3201,7 +3283,7 @@ class Array(ClassSelector["AT"]):
3201
3283
  **params: Unpack[_ClassSelectorKwargs]
3202
3284
  ) -> None:
3203
3285
  import numpy
3204
- super().__init__( # type: ignore[misc, call-overload]
3286
+ super().__init__( # type: ignore[misc, call-overload] # ty: ignore[no-matching-overload]
3205
3287
  default=default, # type: ignore[arg-type]
3206
3288
  class_=numpy.ndarray, # type: ignore[arg-type]
3207
3289
  is_instance=True,
@@ -3290,6 +3372,16 @@ class DataFrame(ClassSelector["DF"]):
3290
3372
  ) -> None:
3291
3373
  ...
3292
3374
 
3375
+ @t.overload
3376
+ def __init__(
3377
+ self: DataFrame[pd.DataFrame | None],
3378
+ default: None = None,
3379
+ *,
3380
+ allow_None: t.Literal[False] = False,
3381
+ **kwargs: Unpack[_DataFrameInitKwargs]
3382
+ ) -> None:
3383
+ ...
3384
+
3293
3385
  def __init__(
3294
3386
  self,
3295
3387
  default: pd.DataFrame | None = t.cast("pd.DataFrame | None", Undefined), # pyrefly: ignore[bad-argument-type]
@@ -3596,7 +3688,7 @@ class List(Parameter[_T]):
3596
3688
 
3597
3689
  def _validate_bounds(self, val, bounds):
3598
3690
  """Check that the list is of the right length and has the right contents."""
3599
- if bounds is None or (val is None and self.allow_None):
3691
+ if bounds is None or val is None:
3600
3692
  return
3601
3693
  min_length, max_length = bounds
3602
3694
  l = len(val)
@@ -3761,7 +3853,7 @@ class Path(Parameter[_T]):
3761
3853
  __slots__ = ['search_paths', 'check_exists']
3762
3854
 
3763
3855
  _slot_defaults = dict(
3764
- Parameter._slot_defaults, check_exists=True,
3856
+ Parameter._slot_defaults, check_exists=True, search_paths=None
3765
3857
  )
3766
3858
 
3767
3859
  search_paths: list[str | PathLike] | None
@@ -3774,9 +3866,9 @@ class Path(Parameter[_T]):
3774
3866
  self: Path[PathLike | str],
3775
3867
  default: PathLike | str = pathlib.Path(""),
3776
3868
  *,
3777
- allow_None: t.Literal[False] = False,
3778
3869
  search_paths: list[str | PathLike] | None = None,
3779
3870
  check_exists: bool = True,
3871
+ allow_None: t.Literal[False] = False,
3780
3872
  doc: str | None = None,
3781
3873
  label: str | None = None,
3782
3874
  precedence: float | None = None,
@@ -3795,7 +3887,7 @@ class Path(Parameter[_T]):
3795
3887
  @t.overload
3796
3888
  def __init__(
3797
3889
  self: Path[PathLike | str | None],
3798
- default: None = None,
3890
+ default: PathLike | str = pathlib.Path(""),
3799
3891
  *,
3800
3892
  allow_None: t.Literal[True] = True,
3801
3893
  **kwargs: Unpack[_PathInitKwargs]
@@ -3805,7 +3897,7 @@ class Path(Parameter[_T]):
3805
3897
  @t.overload
3806
3898
  def __init__(
3807
3899
  self: Path[PathLike | str | None],
3808
- default: PathLike | str = pathlib.Path(""),
3900
+ default: PathLike | str | None = None,
3809
3901
  *,
3810
3902
  allow_None: t.Literal[True] = True,
3811
3903
  **kwargs: Unpack[_PathInitKwargs]
@@ -3873,8 +3965,7 @@ class Path(Parameter[_T]):
3873
3965
  return state
3874
3966
 
3875
3967
 
3876
-
3877
- class Filename(Path):
3968
+ class Filename(Path[_T]):
3878
3969
  """
3879
3970
  Parameter that can be set to a string specifying the path of a file.
3880
3971
 
@@ -3889,11 +3980,67 @@ class Filename(Path):
3889
3980
  is ``None``).
3890
3981
  """
3891
3982
 
3983
+ if t.TYPE_CHECKING:
3984
+
3985
+ @t.overload
3986
+ def __init__(
3987
+ self: Filename[PathLike | str],
3988
+ default: PathLike | str = pathlib.Path(""),
3989
+ *,
3990
+ allow_None: t.Literal[False] = False,
3991
+ search_paths: list[str | PathLike] | None = None,
3992
+ check_exists: bool = True,
3993
+ doc: str | None = None,
3994
+ label: str | None = None,
3995
+ precedence: float | None = None,
3996
+ instantiate: bool = False,
3997
+ constant: bool = False,
3998
+ readonly: bool = False,
3999
+ pickle_default_value: bool = True,
4000
+ per_instance: bool = True,
4001
+ allow_refs: bool = False,
4002
+ nested_refs: bool = False,
4003
+ default_factory: t.Callable[[], t.Any] | None = None,
4004
+ metadata: dict[str, t.Any] | None = None,
4005
+ ) -> None:
4006
+ ...
4007
+
4008
+ @t.overload
4009
+ def __init__(
4010
+ self: Filename[PathLike | str | None],
4011
+ default: PathLike | str = pathlib.Path(""),
4012
+ *,
4013
+ allow_None: t.Literal[True] = True,
4014
+ **kwargs: Unpack[_PathInitKwargs]
4015
+ ) -> None:
4016
+ ...
4017
+
4018
+ @t.overload
4019
+ def __init__(
4020
+ self: Filename[PathLike | str | None],
4021
+ default: PathLike | str | None = None,
4022
+ *,
4023
+ allow_None: t.Literal[True] = True,
4024
+ **kwargs: Unpack[_PathInitKwargs]
4025
+ ) -> None:
4026
+ ...
4027
+
4028
+ def __init__(
4029
+ self,
4030
+ default: str | PathLike | None = t.cast("str | PathLike | None", Undefined), # pyrefly: ignore[bad-argument-type]
4031
+ *,
4032
+ allow_None: bool = t.cast("bool", Undefined), # pyrefly: ignore[bad-argument-type]
4033
+ **kwargs: Unpack[_PathInitKwargs]
4034
+ ) -> None:
4035
+ super().__init__( # type: ignore[misc, call-overload] # ty: ignore[no-matching-overload]
4036
+ default=default, allow_None=allow_None, **kwargs # type: ignore[arg-type]
4037
+ )
4038
+
3892
4039
  def _resolve(self, path):
3893
4040
  return resolve_path(path=path, path_to_file=True, search_paths=self.search_paths)
3894
4041
 
3895
4042
 
3896
- class Foldername(Path):
4043
+ class Foldername(Path[_T]):
3897
4044
  """
3898
4045
  Parameter that can be set to a string specifying the path of a folder.
3899
4046
 
@@ -3908,6 +4055,62 @@ class Foldername(Path):
3908
4055
  is ``None``).
3909
4056
  """
3910
4057
 
4058
+ if t.TYPE_CHECKING:
4059
+
4060
+ @t.overload
4061
+ def __init__(
4062
+ self: Foldername[PathLike | str],
4063
+ default: PathLike | str = pathlib.Path(""),
4064
+ *,
4065
+ allow_None: t.Literal[False] = False,
4066
+ search_paths: list[str | PathLike] | None = None,
4067
+ check_exists: bool = True,
4068
+ doc: str | None = None,
4069
+ label: str | None = None,
4070
+ precedence: float | None = None,
4071
+ instantiate: bool = False,
4072
+ constant: bool = False,
4073
+ readonly: bool = False,
4074
+ pickle_default_value: bool = True,
4075
+ per_instance: bool = True,
4076
+ allow_refs: bool = False,
4077
+ nested_refs: bool = False,
4078
+ default_factory: t.Callable[[], t.Any] | None = None,
4079
+ metadata: dict[str, t.Any] | None = None,
4080
+ ) -> None:
4081
+ ...
4082
+
4083
+ @t.overload
4084
+ def __init__(
4085
+ self: Foldername[PathLike | str | None],
4086
+ default: PathLike | str = pathlib.Path(""),
4087
+ *,
4088
+ allow_None: t.Literal[True] = True,
4089
+ **kwargs: Unpack[_PathInitKwargs]
4090
+ ) -> None:
4091
+ ...
4092
+
4093
+ @t.overload
4094
+ def __init__(
4095
+ self: Foldername[PathLike | str | None],
4096
+ default: PathLike | str | None = None,
4097
+ *,
4098
+ allow_None: t.Literal[True] = True,
4099
+ **kwargs: Unpack[_PathInitKwargs]
4100
+ ) -> None:
4101
+ ...
4102
+
4103
+ def __init__(
4104
+ self,
4105
+ default: str | PathLike | None = t.cast("str | PathLike | None", Undefined), # pyrefly: ignore[bad-argument-type]
4106
+ *,
4107
+ allow_None: bool = t.cast("bool", Undefined), # pyrefly: ignore[bad-argument-type]
4108
+ **kwargs: Unpack[_PathInitKwargs]
4109
+ ) -> None:
4110
+ super().__init__( # type: ignore[misc, call-overload] # ty: ignore[no-matching-overload]
4111
+ default=default, allow_None=allow_None, **kwargs # type: ignore[arg-type]
4112
+ )
4113
+
3911
4114
  def _resolve(self, path):
3912
4115
  return resolve_path(path=path, path_to_file=False, search_paths=self.search_paths)
3913
4116
 
@@ -4031,9 +4234,9 @@ class Color(Parameter[_T]):
4031
4234
  )
4032
4235
 
4033
4236
  def _validate_allow_named(self, val, allow_named):
4034
- if (val is None and self.allow_None):
4237
+ if val is None:
4035
4238
  return
4036
- is_hex = re.match('^#?(([0-9a-fA-F]{2}){3}|([0-9a-fA-F]){3})$', val)
4239
+ is_hex = re.fullmatch('^#?(([0-9a-fA-F]{2}){3}|([0-9a-fA-F]){3})$', val)
4037
4240
  if self.allow_named:
4038
4241
  if not is_hex and val.lower() not in self._named_colors:
4039
4242
  raise ValueError(
@@ -4114,9 +4317,9 @@ class Bytes(Parameter[_T]):
4114
4317
  self._validate(self.default)
4115
4318
 
4116
4319
  def _validate_regex(self, val, regex):
4117
- if (val is None and self.allow_None):
4320
+ if val is None or regex is None:
4118
4321
  return
4119
- if regex is not None and re.match(regex, val) is None:
4322
+ if re.fullmatch(regex, val) is None:
4120
4323
  raise ValueError(
4121
4324
  f"{_validate_error_prefix(self)} value {val!r} "
4122
4325
  f"does not match regex {regex!r}."
@@ -0,0 +1,426 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import typing as t
5
+ import pathlib
6
+ from datetime import date, datetime
7
+ from typing_extensions import assert_type
8
+
9
+ import numpy as np
10
+ import param
11
+ import pandas
12
+
13
+
14
+ class ParameterType(param.Parameterized):
15
+ parameter = param.Parameter()
16
+ optional_parameter = param.Parameter(default=None, allow_None=True)
17
+
18
+ ptypes = ParameterType()
19
+ assert_type(ptypes.parameter, t.Any)
20
+ assert_type(ptypes.optional_parameter, t.Any)
21
+
22
+ ParameterType.parameter = "Foo"
23
+ ptypes.parameter = 42
24
+
25
+ ################
26
+ # String Types #
27
+ ################
28
+
29
+ class StringTypes(param.Parameterized):
30
+ string = param.String()
31
+ optional_string = param.String(allow_None=True)
32
+ implicit_optional_string = param.String(default=None)
33
+ empty_string = param.String()
34
+
35
+ nt = param.NumericTuple()
36
+
37
+ stypes = StringTypes()
38
+
39
+ assert_type(stypes.string, str)
40
+ assert_type(stypes.empty_string, str)
41
+ assert_type(stypes.optional_string, str | None)
42
+ assert_type(stypes.implicit_optional_string, str | None)
43
+
44
+ stypes.string = "test"
45
+ stypes.optional_string = None
46
+
47
+ ################
48
+ # Number Types #
49
+ ################
50
+
51
+ class NumberTypes(param.Parameterized):
52
+ number = param.Number(allow_None=False)
53
+ optional_number = param.Number(allow_None=True)
54
+ implicit_optional_number = param.Number(default=None)
55
+ empty_number = param.Number()
56
+ ntypes = NumberTypes()
57
+
58
+ assert_type(ntypes.number, float | int)
59
+ assert_type(ntypes.empty_number, float | int)
60
+ assert_type(ntypes.optional_number, float | int | None)
61
+ assert_type(ntypes.implicit_optional_number, float | int | None)
62
+
63
+ class MagnitudeTypes(param.Parameterized):
64
+ magnitude = param.Magnitude(allow_None=False)
65
+ optional_magnitude = param.Magnitude(allow_None=True)
66
+
67
+ mtypes = MagnitudeTypes()
68
+ assert_type(mtypes.magnitude, float)
69
+ assert_type(mtypes.optional_magnitude, float | None)
70
+
71
+ #################
72
+ # Integer Types #
73
+ #################
74
+
75
+ class IntegerTypes(param.Parameterized):
76
+ integer = param.Integer(allow_None=False)
77
+ optional_integer = param.Integer(allow_None=True)
78
+ implicit_optional_integer = param.Integer(default=None)
79
+ empty_integer = param.Integer()
80
+
81
+ itypes = IntegerTypes()
82
+
83
+ assert_type(itypes.integer, int)
84
+ assert_type(itypes.empty_integer, int)
85
+ assert_type(itypes.optional_integer, int | None)
86
+ assert_type(itypes.implicit_optional_integer, int | None)
87
+
88
+ #################
89
+ # Boolean Types #
90
+ #################
91
+
92
+ class BooleanTypes(param.Parameterized):
93
+ boolean = param.Boolean(allow_None=False)
94
+ optional_boolean = param.Boolean(allow_None=True)
95
+ implicit_optional_boolean = param.Boolean(default=None)
96
+
97
+ btypes = BooleanTypes()
98
+
99
+ assert_type(btypes.boolean, bool)
100
+ assert_type(btypes.optional_boolean, bool | None)
101
+ assert_type(btypes.implicit_optional_boolean, bool | None)
102
+
103
+ class EventTypes(param.Parameterized):
104
+ event = param.Event()
105
+
106
+ etypes = EventTypes()
107
+ assert_type(etypes.event, t.Any)
108
+
109
+ ##############
110
+ # List Types #
111
+ ##############
112
+
113
+ class ListTypes(param.Parameterized):
114
+ list_param = param.List(allow_None=False)
115
+ optional_list_param = param.List(allow_None=True)
116
+ list_int_param = param.List(item_type=int, allow_None=False)
117
+ optional_list_int_param = param.List(item_type=int, allow_None=True)
118
+ empty_list = param.List()
119
+
120
+ ListTypes.list_param = []
121
+
122
+ ltypes = ListTypes()
123
+
124
+ assert_type(ltypes.empty_list, list[t.Any])
125
+ assert_type(ltypes.list_param, list[t.Any])
126
+ assert_type(ltypes.optional_list_param, list[t.Any] | None)
127
+ assert_type(ltypes.list_int_param, list[int])
128
+ assert_type(ltypes.optional_list_int_param, list[int] | None)
129
+
130
+ class Test(param.Parameterized):
131
+ a = param.Integer()
132
+ b = param.List(item_type=int)
133
+
134
+ tst = Test()
135
+ assert_type(Test.a, int)
136
+ assert_type(Test.b, list[int])
137
+ assert_type(tst.a, int)
138
+ assert_type(tst.b, list[int])
139
+
140
+ ##############
141
+ # Dict Types #
142
+ ##############
143
+
144
+ class DictTypes(param.Parameterized):
145
+ dict_param = param.Dict(allow_None=False)
146
+ optional_dict_param = param.Dict(allow_None=True)
147
+
148
+ dtypes = DictTypes()
149
+
150
+ assert_type(dtypes.dict_param, dict)
151
+ assert_type(dtypes.optional_dict_param, dict | None)
152
+
153
+ ###############
154
+ # Dynamic Type #
155
+ ###############
156
+
157
+ class DynamicTypes(param.Parameterized):
158
+ dynamic = param.Dynamic(default=1)
159
+ optional_dynamic = param.Dynamic(default=None, allow_None=True)
160
+
161
+ dytypes = DynamicTypes()
162
+ assert_type(dytypes.dynamic, t.Any)
163
+ assert_type(dytypes.optional_dynamic, t.Any | None)
164
+
165
+ ###############
166
+ # Tuple Types #
167
+ ###############
168
+
169
+ class TupleTypes(param.Parameterized):
170
+ tuple_param = param.Tuple(length=2, allow_None=False)
171
+ optional_tuple_param = param.Tuple(length=2, allow_None=True)
172
+
173
+ ttypes = TupleTypes()
174
+
175
+ assert_type(ttypes.tuple_param, tuple[t.Any, ...])
176
+ assert_type(ttypes.optional_tuple_param, tuple[t.Any, ...] | None)
177
+
178
+ class NumericTupleTypes(param.Parameterized):
179
+ numeric_tuple = param.NumericTuple(allow_None=False)
180
+ optional_numeric_tuple = param.NumericTuple(allow_None=True)
181
+ empty_numeric_tuple = param.NumericTuple()
182
+
183
+ nttypes = NumericTupleTypes()
184
+ assert_type(nttypes.numeric_tuple, tuple[float, ...])
185
+ assert_type(nttypes.optional_numeric_tuple, tuple[float, ...] | None)
186
+ assert_type(nttypes.empty_numeric_tuple, tuple[float, ...])
187
+
188
+ class XYCoordinatesTypes(param.Parameterized):
189
+ xy = param.XYCoordinates(allow_None=False)
190
+ optional_xy = param.XYCoordinates(allow_None=True)
191
+
192
+ xytypes = XYCoordinatesTypes()
193
+ assert_type(xytypes.xy, tuple[float, float])
194
+ assert_type(xytypes.optional_xy, tuple[float, float] | None)
195
+
196
+ class RangeTypes(param.Parameterized):
197
+ range_param = param.Range(allow_None=False)
198
+ optional_range_param = param.Range(allow_None=True)
199
+
200
+ rtypes = RangeTypes()
201
+ assert_type(rtypes.range_param, tuple[float, float])
202
+ assert_type(rtypes.optional_range_param, tuple[float, float] | None)
203
+
204
+ ##############
205
+ # Date Types #
206
+ ##############
207
+
208
+ class DateTypes(param.Parameterized):
209
+ date_param = param.Date(default=datetime(2024, 1, 1), allow_None=False)
210
+ optional_date_param = param.Date(default=None, allow_None=True)
211
+ calendar_date_param = param.CalendarDate(default=date(2024, 1, 1), allow_None=False)
212
+ optional_calendar_date_param = param.CalendarDate(default=None, allow_None=True)
213
+
214
+ dtypes = DateTypes()
215
+ assert_type(dtypes.date_param, datetime | date)
216
+ assert_type(dtypes.optional_date_param, datetime | date | None)
217
+ assert_type(dtypes.calendar_date_param, date)
218
+ assert_type(dtypes.optional_calendar_date_param, date | None)
219
+
220
+ class DateRangeTypes(param.Parameterized):
221
+ date_range = param.DateRange(
222
+ default=(datetime(2024, 1, 1), datetime(2024, 1, 2)),
223
+ allow_None=False,
224
+ )
225
+ optional_date_range = param.DateRange(default=None, allow_None=True)
226
+ calendar_date_range = param.CalendarDateRange(
227
+ default=(date(2024, 1, 1), date(2024, 1, 2)),
228
+ allow_None=False,
229
+ )
230
+ optional_calendar_date_range = param.CalendarDateRange(default=None, allow_None=True)
231
+
232
+ drtypes = DateRangeTypes()
233
+ assert_type(drtypes.date_range, tuple[datetime | date, datetime | date])
234
+ assert_type(drtypes.optional_date_range, tuple[datetime | date, datetime | date] | None)
235
+ assert_type(drtypes.calendar_date_range, tuple[date, date])
236
+ assert_type(drtypes.optional_calendar_date_range, tuple[date, date] | None)
237
+
238
+ ###############
239
+ # Class Types #
240
+ ###############
241
+
242
+ class Foo: pass
243
+
244
+ class ClassTypes(param.Parameterized):
245
+ foo = param.ClassSelector(class_=Foo, allow_None=False, default=Foo())
246
+ optional_foo = param.ClassSelector(class_=Foo, allow_None=True)
247
+ no_none_foo = param.ClassSelector(class_=Foo, allow_None=param.parameters.NoNone)
248
+
249
+ ctypes = ClassTypes()
250
+
251
+ assert_type(ctypes.foo, Foo)
252
+ assert_type(ctypes.optional_foo, Foo | None)
253
+ assert_type(ctypes.no_none_foo, Foo)
254
+
255
+ class SelectorBaseTypes(param.Parameterized):
256
+ selector_base = param.SelectorBase(default=1, allow_None=False)
257
+ optional_selector_base = param.SelectorBase(default=None, allow_None=True)
258
+
259
+ sbtypes = SelectorBaseTypes()
260
+ assert_type(sbtypes.selector_base, t.Any)
261
+ assert_type(sbtypes.optional_selector_base, t.Any)
262
+
263
+ ##############
264
+ # Type
265
+ ##############
266
+
267
+ class TypeTypes(param.Parameterized):
268
+ type_param = param.ClassSelector(
269
+ allow_None=False, is_instance=False, class_=Foo, default=Foo
270
+ )
271
+ optional_type_param = param.ClassSelector(
272
+ allow_None=True, is_instance=False, class_=Foo
273
+ )
274
+
275
+ ttypes = TypeTypes()
276
+ assert_type(ttypes.type_param, type[Foo])
277
+ assert_type(ttypes.optional_type_param, type[Foo] | None)
278
+
279
+
280
+ ##############
281
+ # DataFrame #
282
+ ##############
283
+
284
+ class DataFrameTypes(param.Parameterized):
285
+ df = param.DataFrame(default=pandas.DataFrame(), allow_None=False)
286
+ optional_df = param.DataFrame(allow_None=True, rows=3)
287
+ optional_df_by_default = param.DataFrame()
288
+
289
+ dftypes = DataFrameTypes()
290
+ assert_type(dftypes.df, pandas.DataFrame)
291
+ assert_type(dftypes.optional_df, pandas.DataFrame | None)
292
+ assert_type(dftypes.optional_df_by_default, pandas.DataFrame | None) # type: ignore
293
+
294
+ ###########
295
+ # Series #
296
+ ###########
297
+
298
+ class SeriesTypes(param.Parameterized):
299
+ series = param.Series(allow_None=False)
300
+ optional_series = param.Series(allow_None=True)
301
+
302
+ stypes = SeriesTypes()
303
+ assert_type(stypes.series, pandas.Series)
304
+ assert_type(stypes.optional_series, pandas.Series | None)
305
+
306
+ ###########
307
+ # Array #
308
+ ###########
309
+
310
+ class ArrayTypes(param.Parameterized):
311
+ array = param.Array(allow_None=False)
312
+ optional_array = param.Array(default=None)
313
+
314
+ atypes = ArrayTypes()
315
+ assert_type(atypes.array, np.ndarray)
316
+ assert_type(atypes.optional_array, np.ndarray | None)
317
+
318
+ ##################
319
+ # Callable Types #
320
+ ##################
321
+
322
+ def _callback() -> int:
323
+ return 1
324
+
325
+ class CallableTypes(param.Parameterized):
326
+ callable_param = param.Callable(default=_callback, allow_None=False)
327
+ optional_callable_param = param.Callable(default=None, allow_None=True)
328
+ action = param.Action(default=_callback, allow_None=False)
329
+ optional_action = param.Action(default=None, allow_None=True)
330
+
331
+ catypes = CallableTypes()
332
+ assert_type(catypes.callable_param, t.Callable[..., t.Any])
333
+ assert_type(catypes.optional_callable_param, t.Callable[..., t.Any] | None)
334
+ assert_type(catypes.action, t.Callable[[], t.Any])
335
+ assert_type(catypes.optional_action, t.Callable[[], t.Any] | None)
336
+
337
+ ##################
338
+ # Composite Type #
339
+ ##################
340
+
341
+ class CompositeTypes(param.Parameterized):
342
+ value = param.Number(default=1)
343
+ comp = param.Composite(attribs=["value"])
344
+
345
+ comptypes = CompositeTypes()
346
+ assert_type(comptypes.comp, list[t.Any])
347
+
348
+ ##################
349
+ # Selector Types #
350
+ ##################
351
+
352
+ class SelectorTypes(param.Parameterized):
353
+ selector = param.Selector(objects=[1,2,3], allow_None=False)
354
+ optional_selector = param.Selector(objects=[1,2,3], allow_None=True)
355
+
356
+ stypes = SelectorTypes()
357
+ assert_type(stypes.selector, t.Any)
358
+ assert_type(stypes.optional_selector, t.Any)
359
+
360
+ class ObjectSelectorTypes(param.Parameterized):
361
+ object_selector = param.ObjectSelector(default=1, objects=[1, 2, 3], allow_None=False)
362
+ optional_object_selector = param.ObjectSelector(
363
+ default=None, objects=[1, 2, 3], allow_None=True
364
+ )
365
+
366
+ ostypes = ObjectSelectorTypes()
367
+ assert_type(ostypes.object_selector, t.Any)
368
+ assert_type(ostypes.optional_object_selector, t.Any)
369
+
370
+ class FileSelectorTypes(param.Parameterized):
371
+ file_selector = param.FileSelector(path="*")
372
+ list_selector = param.ListSelector(objects=["a", "b"], allow_None=True)
373
+ multi_file_selector = param.MultiFileSelector(path="*")
374
+
375
+ fstypes = FileSelectorTypes()
376
+ assert_type(fstypes.file_selector, t.Any)
377
+ assert_type(fstypes.list_selector, t.Any)
378
+ assert_type(fstypes.multi_file_selector, t.Any)
379
+
380
+ ##############
381
+ # Path Types #
382
+ ##############
383
+
384
+ class PathTypes(param.Parameterized):
385
+ path_param = param.Path(default=pathlib.Path("."), allow_None=False)
386
+ optional_path_param = param.Path(default=None, allow_None=True)
387
+ filename = param.Filename(default=pathlib.Path("type_tests.py"), allow_None=False)
388
+ optional_filename = param.Filename(default=None, allow_None=True)
389
+ foldername = param.Foldername(default=pathlib.Path("."), allow_None=False)
390
+ optional_foldername = param.Foldername(default=None, allow_None=True)
391
+
392
+ ptypes = PathTypes()
393
+ assert_type(ptypes.path_param, os.PathLike | str)
394
+ assert_type(ptypes.optional_path_param, os.PathLike | str | None)
395
+ assert_type(ptypes.filename, os.PathLike | str)
396
+ assert_type(ptypes.optional_filename, os.PathLike | str | None)
397
+ assert_type(ptypes.foldername, os.PathLike | str)
398
+ assert_type(ptypes.optional_foldername, os.PathLike | str | None)
399
+
400
+ ##############
401
+ # List Types #
402
+ ##############
403
+
404
+ class HookListTypes(param.Parameterized):
405
+ hook_list = param.HookList(default=[], allow_None=False)
406
+ optional_hook_list = param.HookList(default=None, allow_None=True)
407
+
408
+ hltypes = HookListTypes()
409
+ assert_type(hltypes.hook_list, t.Any)
410
+ assert_type(hltypes.optional_hook_list, t.Any)
411
+
412
+ #####################
413
+ # String-like Types #
414
+ #####################
415
+
416
+ class ColorAndBytesTypes(param.Parameterized):
417
+ color = param.Color(allow_None=False)
418
+ optional_color = param.Color(allow_None=True)
419
+ bytes_param = param.Bytes(allow_None=False)
420
+ optional_bytes_param = param.Bytes(allow_None=True)
421
+
422
+ cbtypes = ColorAndBytesTypes()
423
+ assert_type(cbtypes.color, str)
424
+ assert_type(cbtypes.optional_color, str | None)
425
+ assert_type(cbtypes.bytes_param, bytes)
426
+ assert_type(cbtypes.optional_bytes_param, bytes | None)
@@ -0,0 +1 @@
1
+ {}
@@ -5,7 +5,8 @@ import pytest
5
5
 
6
6
  try:
7
7
  import cloudpickle
8
- except ModuleNotFoundError:
8
+ except (AttributeError, ModuleNotFoundError):
9
+ # Not installed or PyPy on Windows
9
10
  cloudpickle = None
10
11
  try:
11
12
  import numpy as np
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes