param 2.4.0a0__tar.gz → 2.4.0rc0__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.
- {param-2.4.0a0 → param-2.4.0rc0}/PKG-INFO +1 -1
- {param-2.4.0a0 → param-2.4.0rc0}/param/_version.py +2 -2
- {param-2.4.0a0 → param-2.4.0rc0}/param/depends.py +28 -23
- {param-2.4.0a0 → param-2.4.0rc0}/param/parameterized.py +115 -68
- {param-2.4.0a0 → param-2.4.0rc0}/param/parameters.py +69 -24
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testparameterizedobject.py +21 -0
- {param-2.4.0a0 → param-2.4.0rc0}/.gitignore +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/LICENSE.txt +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/README.md +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/numbergen/__init__.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/param/__init__.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/param/_utils.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/param/display.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/param/ipython.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/param/py.typed +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/param/reactive.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/param/serializer.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/param/version.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/pyproject.toml +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/__init__.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/conftest.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testaddparameter.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testbind.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testbooleanparam.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testbytesparam.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testcalendardateparam.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testcalendardaterangeparam.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testcallable.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testclassselector.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testcolorparameter.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testcomparator.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testcompositeparams.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testcustomparam.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testdateparam.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testdaterangeparam.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testdefaultfactory.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testdefaults.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testdeprecations.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testdynamicparams.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testfiledeserialization.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testfileselector.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testimports.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testipythonmagic.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testjsonserialization.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testlist.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testlistselector.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testmultifileselector.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testnumbergen.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testnumberparameter.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testnumpy.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testobjectselector.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testpandas.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testparamdepends.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testparameter.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testparameterizedrepr.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testparamoutput.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testparamunion.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testpathparam.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testpickle.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testrangeparameter.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testreactive.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testrefs.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testreprhtml.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testselector.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testsignatures.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/teststringparam.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testtimedependent.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testtupleparam.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testutils.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testversion.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/testwatch.py +0 -0
- {param-2.4.0a0 → param-2.4.0rc0}/tests/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: param
|
|
3
|
-
Version: 2.4.
|
|
3
|
+
Version: 2.4.0rc0
|
|
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
|
|
@@ -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.
|
|
22
|
-
__version_tuple__ = version_tuple = (2, 4, 0, '
|
|
21
|
+
__version__ = version = '2.4.0rc0'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 4, 0, 'rc0')
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -15,11 +15,12 @@ if t.TYPE_CHECKING:
|
|
|
15
15
|
from collections.abc import AsyncGenerator, Callable, Generator
|
|
16
16
|
|
|
17
17
|
_Y = t.TypeVar("_Y")
|
|
18
|
-
_S = t.TypeVar("_S")
|
|
19
18
|
_T = t.TypeVar("_T")
|
|
20
19
|
|
|
21
20
|
_P = t.ParamSpec("_P")
|
|
21
|
+
_FullP = t.ParamSpec("_FullP")
|
|
22
22
|
_R = t.TypeVar("_R", covariant=True)
|
|
23
|
+
_S = t.TypeVar("_S")
|
|
23
24
|
Dependency = Parameter | str
|
|
24
25
|
|
|
25
26
|
class DependencyInfo(t.TypedDict):
|
|
@@ -28,6 +29,10 @@ class DependencyInfo(t.TypedDict):
|
|
|
28
29
|
watch: bool
|
|
29
30
|
on_init: bool
|
|
30
31
|
|
|
32
|
+
class _DepsFn(t.Protocol[_FullP, _R]):
|
|
33
|
+
_dinfo: DependencyInfo
|
|
34
|
+
def __call__(self, *args: _FullP.args, **kwargs: _FullP.kwargs) -> _R: ...
|
|
35
|
+
|
|
31
36
|
class DependsFunc(t.Protocol[_P, _R]):
|
|
32
37
|
_dinfo: DependencyInfo
|
|
33
38
|
def __call__(self, *args: _P.args, **kwargs: _P.kwargs) -> _R: ...
|
|
@@ -35,25 +40,25 @@ class DependsFunc(t.Protocol[_P, _R]):
|
|
|
35
40
|
|
|
36
41
|
@t.overload
|
|
37
42
|
def depends(
|
|
38
|
-
func: Callable[_P, _R], /, *dependencies: Dependency, watch: bool = False, on_init: bool = False, **kw: Dependency
|
|
43
|
+
func: Callable[t.Concatenate[_S, _P], _R], /, *dependencies: Dependency, watch: bool = False, on_init: bool = False, **kw: Dependency
|
|
39
44
|
) -> DependsFunc[_P, _R]:
|
|
40
45
|
...
|
|
41
46
|
|
|
42
47
|
@t.overload
|
|
43
48
|
def depends(
|
|
44
49
|
*dependencies: str, watch: bool = False, on_init: bool = False
|
|
45
|
-
) -> Callable[[Callable[_P, _R]], DependsFunc[_P, _R]]:
|
|
50
|
+
) -> Callable[[Callable[t.Concatenate[_S, _P], _R]], DependsFunc[_P, _R]]:
|
|
46
51
|
...
|
|
47
52
|
|
|
48
53
|
@t.overload
|
|
49
54
|
def depends(
|
|
50
55
|
*dependencies: Parameter, watch: bool = False, on_init: bool = False, **kw: Parameter
|
|
51
|
-
) -> Callable[[Callable[_P, _R]], DependsFunc[_P, _R]]:
|
|
56
|
+
) -> Callable[[Callable[t.Concatenate[_S, _P], _R]], DependsFunc[_P, _R]]:
|
|
52
57
|
...
|
|
53
58
|
|
|
54
59
|
def depends(
|
|
55
|
-
*dependencies: Dependency | Callable[_P, _R], watch: bool = False, on_init: bool = False, **kw: Dependency
|
|
56
|
-
) -> DependsFunc[_P, _R] | Callable[[Callable[_P, _R]], DependsFunc[_P, _R]]:
|
|
60
|
+
*dependencies: Dependency | Callable[t.Concatenate[_S, _P], _R], watch: bool = False, on_init: bool = False, **kw: Dependency
|
|
61
|
+
) -> DependsFunc[_P, _R] | Callable[[Callable[t.Concatenate[_S, _P], _R]], DependsFunc[_P, _R]]:
|
|
57
62
|
"""
|
|
58
63
|
Annotates a function or :class:`Parameterized` method to express its dependencies.
|
|
59
64
|
|
|
@@ -74,51 +79,51 @@ def depends(
|
|
|
74
79
|
|
|
75
80
|
"""
|
|
76
81
|
if dependencies and callable(dependencies[0]) and not isinstance(dependencies[0], (str, Parameter)):
|
|
77
|
-
func = t.cast("Callable[_P, _R]", dependencies[0])
|
|
82
|
+
func = t.cast("Callable[t.Concatenate[_S, _P], _R]", dependencies[0])
|
|
78
83
|
deps = t.cast("tuple[Dependency, ...]", dependencies[1:])
|
|
79
|
-
return _depends_impl(func, *deps, watch=watch, on_init=on_init, **kw)
|
|
84
|
+
return t.cast("DependsFunc[_P, _R]", _depends_impl(func, *deps, watch=watch, on_init=on_init, **kw))
|
|
80
85
|
|
|
81
86
|
deps = t.cast("tuple[Dependency, ...]", dependencies)
|
|
82
87
|
|
|
83
|
-
def _decorator(func: Callable[_P, _R]) -> DependsFunc[_P, _R]:
|
|
84
|
-
return _depends_impl(func, *deps, watch=watch, on_init=on_init, **kw)
|
|
88
|
+
def _decorator(func: Callable[t.Concatenate[_S, _P], _R]) -> DependsFunc[_P, _R]:
|
|
89
|
+
return t.cast("DependsFunc[_P, _R]", _depends_impl(func, *deps, watch=watch, on_init=on_init, **kw))
|
|
85
90
|
|
|
86
91
|
return _decorator
|
|
87
92
|
|
|
88
93
|
|
|
89
94
|
def _depends_impl(
|
|
90
|
-
func: Callable[
|
|
91
|
-
) ->
|
|
95
|
+
func: Callable[_FullP, _R], /, *dependencies: Dependency, watch: bool = False, on_init: bool = False, **kw: Dependency
|
|
96
|
+
) -> _DepsFn[_FullP, _R]:
|
|
92
97
|
dependencies, kw = (
|
|
93
98
|
tuple(transform_reference(arg) for arg in dependencies),
|
|
94
99
|
{key: transform_reference(arg) for key, arg in kw.items()}
|
|
95
100
|
)
|
|
96
101
|
|
|
97
102
|
if inspect.isgeneratorfunction(func):
|
|
98
|
-
func_gen = t.cast("Callable[
|
|
103
|
+
func_gen = t.cast("Callable[_FullP, Generator[t.Any, t.Any, t.Any]]", func)
|
|
99
104
|
@wraps(func)
|
|
100
105
|
def _depends_gen(*args, **kw):
|
|
101
106
|
for val in func_gen(*args, **kw):
|
|
102
107
|
yield val
|
|
103
|
-
_depends = t.cast("Callable[
|
|
108
|
+
_depends = t.cast("Callable[_FullP, _R]", _depends_gen)
|
|
104
109
|
elif inspect.isasyncgenfunction(func):
|
|
105
|
-
func_agen = t.cast("Callable[
|
|
110
|
+
func_agen = t.cast("Callable[_FullP, AsyncGenerator[t.Any, t.Any]]", func)
|
|
106
111
|
@wraps(func)
|
|
107
112
|
async def _depends_async_gen(*args, **kw):
|
|
108
113
|
async for val in func_agen(*args, **kw):
|
|
109
114
|
yield val
|
|
110
|
-
_depends = t.cast("Callable[
|
|
115
|
+
_depends = t.cast("Callable[_FullP, _R]", _depends_async_gen)
|
|
111
116
|
elif iscoroutinefunction(func):
|
|
112
|
-
F = t.cast("Callable[
|
|
117
|
+
F = t.cast("Callable[_FullP, t.Awaitable[_R]]", func)
|
|
113
118
|
@wraps(func)
|
|
114
119
|
async def _depends_coro(*args, **kw):
|
|
115
120
|
return await F(*args, **kw)
|
|
116
|
-
_depends = t.cast("Callable[
|
|
121
|
+
_depends = t.cast("Callable[_FullP, _R]", _depends_coro)
|
|
117
122
|
else:
|
|
118
123
|
@wraps(func)
|
|
119
124
|
def _depends_sync(*args, **kw):
|
|
120
125
|
return func(*args, **kw)
|
|
121
|
-
_depends = t.cast("Callable[
|
|
126
|
+
_depends = t.cast("Callable[_FullP, _R]", _depends_sync)
|
|
122
127
|
|
|
123
128
|
deps = list(dependencies)+list(kw.values())
|
|
124
129
|
string_specs = False
|
|
@@ -155,7 +160,7 @@ def _depends_impl(
|
|
|
155
160
|
_dinfo.update({'dependencies': dependencies,
|
|
156
161
|
'kw': kw, 'watch': watch, 'on_init': on_init})
|
|
157
162
|
|
|
158
|
-
typed_depends = t.cast("
|
|
163
|
+
typed_depends = t.cast("_DepsFn[_FullP, _R]", _depends)
|
|
159
164
|
typed_depends._dinfo = _dinfo
|
|
160
165
|
|
|
161
166
|
if string_specs or not watch:
|
|
@@ -196,7 +201,7 @@ def _depends_impl(
|
|
|
196
201
|
def cb_gen(*events: Event):
|
|
197
202
|
args = _resolve_args()
|
|
198
203
|
dep_kwargs = _resolve_kwargs()
|
|
199
|
-
func_gen = t.cast("Callable[
|
|
204
|
+
func_gen = t.cast("Callable[_FullP, Generator[t.Any, t.Any, t.Any]]", func)
|
|
200
205
|
for val in func_gen(*args, **dep_kwargs):
|
|
201
206
|
yield val
|
|
202
207
|
cb = cb_gen
|
|
@@ -204,7 +209,7 @@ def _depends_impl(
|
|
|
204
209
|
async def cb_async_gen(*events: Event):
|
|
205
210
|
args = _resolve_args()
|
|
206
211
|
dep_kwargs = _resolve_kwargs()
|
|
207
|
-
func_agen = t.cast("Callable[
|
|
212
|
+
func_agen = t.cast("Callable[_FullP, AsyncGenerator[t.Any, t.Any]]", func)
|
|
208
213
|
async for val in func_agen(*args, **dep_kwargs):
|
|
209
214
|
yield val
|
|
210
215
|
cb = cb_async_gen
|
|
@@ -212,7 +217,7 @@ def _depends_impl(
|
|
|
212
217
|
async def cb_coro(*events: Event):
|
|
213
218
|
args = _resolve_args()
|
|
214
219
|
dep_kwargs = _resolve_kwargs()
|
|
215
|
-
func_coro = t.cast("Callable[
|
|
220
|
+
func_coro = t.cast("Callable[_FullP, t.Awaitable[t.Any]]", func)
|
|
216
221
|
await func_coro(*args, **dep_kwargs)
|
|
217
222
|
cb = cb_coro
|
|
218
223
|
else:
|
|
@@ -59,7 +59,6 @@ if t.TYPE_CHECKING:
|
|
|
59
59
|
class _StringInitKwargs(_ParameterKwargs, total=False):
|
|
60
60
|
regex: str | re.Pattern[str] | None
|
|
61
61
|
|
|
62
|
-
|
|
63
62
|
_T = t.TypeVar("_T")
|
|
64
63
|
_P = t.ParamSpec("_P")
|
|
65
64
|
_R = t.TypeVar("_R", covariant=True)
|
|
@@ -84,6 +83,8 @@ from ._utils import (
|
|
|
84
83
|
gen_types,
|
|
85
84
|
)
|
|
86
85
|
|
|
86
|
+
_IS_PYPY = sys.implementation.name == "pypy"
|
|
87
|
+
|
|
87
88
|
CRITICAL = 50
|
|
88
89
|
ERROR = 40
|
|
89
90
|
WARNING = 30
|
|
@@ -1189,6 +1190,7 @@ class ParameterMetaclass(type):
|
|
|
1189
1190
|
|
|
1190
1191
|
|
|
1191
1192
|
_UDPATE_PARAMETER_SIGNATURE = _in_ipython() or (os.getenv("PARAM_PARAMETER_SIGNATURE", "false").lower() in ("1" , "true"))
|
|
1193
|
+
_PARAMETER_CACHE_ATTRS = ('instantiate', 'constant', 'default_factory')
|
|
1192
1194
|
|
|
1193
1195
|
|
|
1194
1196
|
class _ParameterBase(metaclass=ParameterMetaclass):
|
|
@@ -1853,6 +1855,8 @@ class Parameter(_ParameterBase, t.Generic[_T]):
|
|
|
1853
1855
|
pass
|
|
1854
1856
|
|
|
1855
1857
|
super().__setattr__(attribute, value)
|
|
1858
|
+
if is_slot and attribute in _PARAMETER_CACHE_ATTRS:
|
|
1859
|
+
self._invalidate_init_cache()
|
|
1856
1860
|
if has_watcher and old is not NotImplemented:
|
|
1857
1861
|
self._trigger_event(attribute, old, value)
|
|
1858
1862
|
|
|
@@ -1867,6 +1871,20 @@ class Parameter(_ParameterBase, t.Generic[_T]):
|
|
|
1867
1871
|
if not self.owner.param._BATCH_WATCH:
|
|
1868
1872
|
self.owner.param._batch_call_watchers()
|
|
1869
1873
|
|
|
1874
|
+
def _invalidate_init_cache(self):
|
|
1875
|
+
try:
|
|
1876
|
+
owner = object.__getattribute__(self, 'owner')
|
|
1877
|
+
except AttributeError:
|
|
1878
|
+
return
|
|
1879
|
+
if owner is None:
|
|
1880
|
+
return
|
|
1881
|
+
private = owner._param__private
|
|
1882
|
+
if not hasattr(private, 'params_to_deepcopy'):
|
|
1883
|
+
return
|
|
1884
|
+
private.params_to_deepcopy = None
|
|
1885
|
+
private.params_to_ref = None
|
|
1886
|
+
private.params_with_default_factory = None
|
|
1887
|
+
|
|
1870
1888
|
def __getattribute__(self, key: str) -> t.Any:
|
|
1871
1889
|
"""
|
|
1872
1890
|
Allow slot values to be Undefined in an "unbound" parameter, i.e. one
|
|
@@ -2011,6 +2029,9 @@ class Parameter(_ParameterBase, t.Generic[_T]):
|
|
|
2011
2029
|
obj._param__private.values[name] = val
|
|
2012
2030
|
self._post_setter(obj, val)
|
|
2013
2031
|
|
|
2032
|
+
if obj is None:
|
|
2033
|
+
self._invalidate_init_cache()
|
|
2034
|
+
|
|
2014
2035
|
if obj is not None:
|
|
2015
2036
|
if not hasattr(obj, '_param__private') or not getattr(obj._param__private, 'initialized', False):
|
|
2016
2037
|
return
|
|
@@ -2105,6 +2126,17 @@ class Parameter(_ParameterBase, t.Generic[_T]):
|
|
|
2105
2126
|
"""
|
|
2106
2127
|
return {slot: getattr(self, slot) for slot in getattr(self.__class__, "_all_slots_", ())}
|
|
2107
2128
|
|
|
2129
|
+
def __copy__(self) -> Parameter:
|
|
2130
|
+
cls = self.__class__
|
|
2131
|
+
duplicate = cls.__new__(cls)
|
|
2132
|
+
if _IS_PYPY:
|
|
2133
|
+
# Workaround for PyPy segfaults (https://github.com/pypy/pypy/issues/5400)
|
|
2134
|
+
duplicate.__setstate__(self.__getstate__())
|
|
2135
|
+
else:
|
|
2136
|
+
for slot in cls._all_slots_:
|
|
2137
|
+
object.__setattr__(duplicate, slot, getattr(self, slot))
|
|
2138
|
+
return duplicate
|
|
2139
|
+
|
|
2108
2140
|
def __setstate__(self, state: dict[str, t.Any]):
|
|
2109
2141
|
# set values of __slots__ (instead of in non-existent __dict__)
|
|
2110
2142
|
for k, v in state.items():
|
|
@@ -2561,21 +2593,17 @@ class Parameters:
|
|
|
2561
2593
|
defined as parameters.
|
|
2562
2594
|
"""
|
|
2563
2595
|
self = self_.self
|
|
2564
|
-
## Deepcopy all 'instantiate=True' parameters
|
|
2565
|
-
params_to_deepcopy = {}
|
|
2566
|
-
params_to_ref = {}
|
|
2567
2596
|
objects = self_._cls_parameters
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
params_to_ref[pname] = p
|
|
2597
|
+
private = self_.cls._param__private
|
|
2598
|
+
params_to_deepcopy = private.params_to_deepcopy or []
|
|
2599
|
+
params_to_ref = private.params_to_ref or []
|
|
2600
|
+
|
|
2601
|
+
if not params and not params_to_deepcopy and not params_to_ref:
|
|
2602
|
+
return {}, {}
|
|
2575
2603
|
|
|
2576
|
-
for p in params_to_deepcopy
|
|
2604
|
+
for p in params_to_deepcopy:
|
|
2577
2605
|
self_._instantiate_param(p)
|
|
2578
|
-
for p in params_to_ref
|
|
2606
|
+
for p in params_to_ref:
|
|
2579
2607
|
self_._instantiate_param(p, deepcopy=False)
|
|
2580
2608
|
|
|
2581
2609
|
## keyword arg setting
|
|
@@ -3108,8 +3136,22 @@ class Parameters:
|
|
|
3108
3136
|
and parameters are rarely added (and cannot be deleted).
|
|
3109
3137
|
"""
|
|
3110
3138
|
cls = self_.cls
|
|
3111
|
-
|
|
3139
|
+
private = cls._param__private
|
|
3140
|
+
pdict = private.params
|
|
3112
3141
|
if pdict:
|
|
3142
|
+
if private.params_to_deepcopy is None or private.params_to_ref is None or private.params_with_default_factory is None:
|
|
3143
|
+
private.params_to_deepcopy = []
|
|
3144
|
+
private.params_to_ref = []
|
|
3145
|
+
private.params_with_default_factory = []
|
|
3146
|
+
for pname, pobj in pdict.items():
|
|
3147
|
+
if pname == 'name':
|
|
3148
|
+
continue
|
|
3149
|
+
if pobj.default_factory is not None:
|
|
3150
|
+
private.params_with_default_factory.append((pname, pobj))
|
|
3151
|
+
elif pobj.instantiate:
|
|
3152
|
+
private.params_to_deepcopy.append(pobj)
|
|
3153
|
+
elif pobj.constant:
|
|
3154
|
+
private.params_to_ref.append(pobj)
|
|
3113
3155
|
return pdict
|
|
3114
3156
|
|
|
3115
3157
|
paramdict = {}
|
|
@@ -3118,12 +3160,28 @@ class Parameters:
|
|
|
3118
3160
|
if isinstance(val, Parameter):
|
|
3119
3161
|
paramdict[name] = val
|
|
3120
3162
|
|
|
3163
|
+
params_to_deepcopy: list[Parameter] = []
|
|
3164
|
+
params_to_ref: list[Parameter] = []
|
|
3165
|
+
params_with_default_factory: list[tuple[str, Parameter]] = []
|
|
3166
|
+
for pname, pobj in paramdict.items():
|
|
3167
|
+
if pname == 'name':
|
|
3168
|
+
continue
|
|
3169
|
+
if pobj.default_factory is not None:
|
|
3170
|
+
params_with_default_factory.append((pname, pobj))
|
|
3171
|
+
elif pobj.instantiate:
|
|
3172
|
+
params_to_deepcopy.append(pobj)
|
|
3173
|
+
elif pobj.constant:
|
|
3174
|
+
params_to_ref.append(pobj)
|
|
3175
|
+
|
|
3121
3176
|
# We only want the cache to be visible to the cls on which
|
|
3122
3177
|
# params() is called, so we mangle the name ourselves at
|
|
3123
3178
|
# runtime (if we were to mangle it now, it would be
|
|
3124
3179
|
# _Parameterized.__params for all classes).
|
|
3125
3180
|
# cls._param__private.params[f'_{cls.__name__}__params'] = paramdict
|
|
3126
|
-
|
|
3181
|
+
private.params = paramdict
|
|
3182
|
+
private.params_to_deepcopy = params_to_deepcopy
|
|
3183
|
+
private.params_to_ref = params_to_ref
|
|
3184
|
+
private.params_with_default_factory = params_with_default_factory
|
|
3127
3185
|
return paramdict
|
|
3128
3186
|
|
|
3129
3187
|
def objects(self_, instance: t.Literal[True, False, 'existing'] = True) -> dict[str, Parameter]:
|
|
@@ -3331,14 +3389,14 @@ class Parameters:
|
|
|
3331
3389
|
"""
|
|
3332
3390
|
self_or_cls = self_.self_or_cls
|
|
3333
3391
|
self_or_cls._Dynamic_time_fn = time_fn # type: ignore[union-attr, ty:invalid-assignment] # pyright: ignore[reportAttributeAccessIssue]
|
|
3334
|
-
|
|
3392
|
+
param_objs = self_.objects('existing')
|
|
3335
3393
|
|
|
3336
|
-
for n, p in
|
|
3394
|
+
for n, p in param_objs.items():
|
|
3337
3395
|
if not hasattr(p, '_value_is_dynamic'):
|
|
3338
3396
|
continue
|
|
3339
3397
|
is_dynamic = p._value_is_dynamic(None, self_._cls) if self_.self is None else p._value_is_dynamic(self_.self)
|
|
3340
3398
|
if is_dynamic:
|
|
3341
|
-
g =
|
|
3399
|
+
g = self_.get_value_generator(n, param_objs)
|
|
3342
3400
|
g._Dynamic_time_fn = time_fn
|
|
3343
3401
|
|
|
3344
3402
|
if sublistattr:
|
|
@@ -3647,12 +3705,12 @@ class Parameters:
|
|
|
3647
3705
|
>>> p.param.values(onlychanged=True)
|
|
3648
3706
|
{'a': 10}
|
|
3649
3707
|
"""
|
|
3650
|
-
|
|
3651
|
-
|
|
3708
|
+
param_objs = self_.objects('existing') # type: ignore[union-attr, ty:unresolved-attribute]
|
|
3709
|
+
|
|
3652
3710
|
vals = []
|
|
3653
|
-
for name, val in
|
|
3654
|
-
value =
|
|
3655
|
-
if name == 'name' and onlychanged and _is_auto_name(self_.cls.__name__, value):
|
|
3711
|
+
for name, val in param_objs.items():
|
|
3712
|
+
value = self_.get_value_generator(name, param_objs)
|
|
3713
|
+
if name == 'name' and onlychanged and isinstance(value, str) and _is_auto_name(self_.cls.__name__, value):
|
|
3656
3714
|
continue
|
|
3657
3715
|
if not onlychanged or not Comparator.is_equal(value, val.default):
|
|
3658
3716
|
vals.append((name, value))
|
|
@@ -3671,25 +3729,15 @@ class Parameters:
|
|
|
3671
3729
|
If name is not dynamic, its current value is returned
|
|
3672
3730
|
(i.e. equivalent to ``getattr(name)``).
|
|
3673
3731
|
"""
|
|
3674
|
-
|
|
3675
|
-
param_ns = cls_or_slf.param
|
|
3676
|
-
param_obj = param_ns.objects('existing').get(name) # type: ignore[union-attr, ty:unresolved-attribute]
|
|
3677
|
-
|
|
3732
|
+
param_obj = self_.objects('existing').get(name) # type: ignore[union-attr, ty:unresolved-attribute]
|
|
3678
3733
|
if not param_obj:
|
|
3679
|
-
return getattr(
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
if isinstance(cls_or_slf,type):
|
|
3683
|
-
cls = cls_or_slf
|
|
3684
|
-
else:
|
|
3685
|
-
slf = cls_or_slf
|
|
3686
|
-
|
|
3687
|
-
if not hasattr(param_obj,'_force'):
|
|
3688
|
-
return param_obj.__get__(slf, cls)
|
|
3734
|
+
return getattr(self_.self_or_cls, name)
|
|
3735
|
+
elif not hasattr(param_obj, '_force'):
|
|
3736
|
+
return param_obj.__get__(self_.self, self_.cls)
|
|
3689
3737
|
else:
|
|
3690
|
-
return param_obj._force(
|
|
3738
|
+
return param_obj._force(self_.self, self_.cls)
|
|
3691
3739
|
|
|
3692
|
-
def get_value_generator(self_, name: str) -> t.Any:
|
|
3740
|
+
def get_value_generator(self_, name: str, parameters: dict[str, Parameter] | None = None) -> t.Any:
|
|
3693
3741
|
"""
|
|
3694
3742
|
Retrieve the value or value-generating object of a named parameter.
|
|
3695
3743
|
|
|
@@ -3732,15 +3780,17 @@ class Parameters:
|
|
|
3732
3780
|
<UniformRandom UniformRandom ...>
|
|
3733
3781
|
"""
|
|
3734
3782
|
cls_or_slf = self_.self_or_cls
|
|
3735
|
-
|
|
3736
|
-
|
|
3783
|
+
if parameters and name in parameters:
|
|
3784
|
+
param_obj: Parameter | None = parameters[name]
|
|
3785
|
+
else:
|
|
3786
|
+
param_obj = self_.objects('existing').get(name) # type: ignore[union-attr, ty:unresolved-attribute]
|
|
3737
3787
|
|
|
3738
3788
|
if not param_obj:
|
|
3739
|
-
value = getattr(cls_or_slf,name)
|
|
3789
|
+
value = getattr(cls_or_slf, name)
|
|
3740
3790
|
|
|
3741
3791
|
# CompositeParameter detected by being a Parameter and having 'attribs'
|
|
3742
3792
|
elif hasattr(param_obj, 'attribs'):
|
|
3743
|
-
value = [
|
|
3793
|
+
value = [self_.get_value_generator(a) for a in param_obj.attribs] # type: ignore[union-attr, ty:unresolved-attribute]
|
|
3744
3794
|
|
|
3745
3795
|
# not a Dynamic Parameter
|
|
3746
3796
|
elif not hasattr(param_obj, '_value_is_dynamic'):
|
|
@@ -3748,10 +3798,9 @@ class Parameters:
|
|
|
3748
3798
|
|
|
3749
3799
|
# Dynamic Parameter...
|
|
3750
3800
|
else:
|
|
3751
|
-
|
|
3752
|
-
if isinstance(cls_or_slf, Parameterized) and name in cls_or_slf._param__private.values:
|
|
3801
|
+
if self_.self is not None and name in self_.self._param__private.values:
|
|
3753
3802
|
# dealing with object and it's been set on this object
|
|
3754
|
-
value =
|
|
3803
|
+
value = self_.self._param__private.values[name]
|
|
3755
3804
|
elif not callable(param_obj.default):
|
|
3756
3805
|
value = getattr(cls_or_slf, name)
|
|
3757
3806
|
else:
|
|
@@ -3796,17 +3845,16 @@ class Parameters:
|
|
|
3796
3845
|
-0.7312715117751976
|
|
3797
3846
|
"""
|
|
3798
3847
|
cls_or_slf = self_.self_or_cls
|
|
3799
|
-
|
|
3800
|
-
param_obj = param_ns.objects('existing').get(name) # type: ignore[union-attr, ty:unresolved-attribute]
|
|
3848
|
+
param_obj = self_.objects('existing').get(name) # type: ignore[union-attr, ty:unresolved-attribute]
|
|
3801
3849
|
|
|
3802
3850
|
if not param_obj:
|
|
3803
3851
|
value = getattr(cls_or_slf,name)
|
|
3804
3852
|
elif hasattr(param_obj,'attribs'):
|
|
3805
|
-
value = [
|
|
3853
|
+
value = [self_.inspect_value(a) for a in param_obj.attribs] # type: ignore[union-attr, ty:unresolved-attribute]
|
|
3806
3854
|
elif not hasattr(param_obj,'_inspect'):
|
|
3807
|
-
value = getattr(cls_or_slf,name)
|
|
3855
|
+
value = getattr(cls_or_slf, name)
|
|
3808
3856
|
else:
|
|
3809
|
-
if isinstance(cls_or_slf,type):
|
|
3857
|
+
if isinstance(cls_or_slf, type):
|
|
3810
3858
|
value = param_obj._inspect(None, cls_or_slf)
|
|
3811
3859
|
else:
|
|
3812
3860
|
value = param_obj._inspect(cls_or_slf, None)
|
|
@@ -5474,6 +5522,9 @@ class _ClassPrivate:
|
|
|
5474
5522
|
'disable_instance_params',
|
|
5475
5523
|
'renamed',
|
|
5476
5524
|
'params',
|
|
5525
|
+
'params_to_deepcopy',
|
|
5526
|
+
'params_to_ref',
|
|
5527
|
+
'params_with_default_factory',
|
|
5477
5528
|
'initialized',
|
|
5478
5529
|
'signature',
|
|
5479
5530
|
'explicit_no_refs',
|
|
@@ -5483,6 +5534,9 @@ class _ClassPrivate:
|
|
|
5483
5534
|
disable_instance_params: bool
|
|
5484
5535
|
renamed: bool
|
|
5485
5536
|
params: dict[str, Parameter]
|
|
5537
|
+
params_to_deepcopy: list[Parameter] | None
|
|
5538
|
+
params_to_ref: list[Parameter] | None
|
|
5539
|
+
params_with_default_factory: list[tuple[str, Parameter]] | None
|
|
5486
5540
|
initialized: bool
|
|
5487
5541
|
signature: inspect.Signature | None
|
|
5488
5542
|
explicit_no_refs: list[str]
|
|
@@ -5506,6 +5560,9 @@ class _ClassPrivate:
|
|
|
5506
5560
|
self.disable_instance_params = disable_instance_params
|
|
5507
5561
|
self.renamed = renamed
|
|
5508
5562
|
self.params = {} if params is None else params
|
|
5563
|
+
self.params_to_deepcopy = None
|
|
5564
|
+
self.params_to_ref = None
|
|
5565
|
+
self.params_with_default_factory = None
|
|
5509
5566
|
self.initialized = False
|
|
5510
5567
|
self.signature = None
|
|
5511
5568
|
self.explicit_no_refs = [] if explicit_no_refs is None else explicit_no_refs
|
|
@@ -5617,15 +5674,7 @@ class _NS:
|
|
|
5617
5674
|
def __get__(self, obj: C | None, objtype: type[C]) -> Parameters:
|
|
5618
5675
|
if obj is None:
|
|
5619
5676
|
return objtype._param__parameters
|
|
5620
|
-
|
|
5621
|
-
ns = objdict.get("_param__parameters") if objdict is not None else None
|
|
5622
|
-
if ns is None:
|
|
5623
|
-
ns = Parameters(objtype, self=obj)
|
|
5624
|
-
if objdict is not None:
|
|
5625
|
-
objdict["_param__parameters"] = ns
|
|
5626
|
-
else:
|
|
5627
|
-
setattr(obj, "_param__parameters", ns)
|
|
5628
|
-
return ns
|
|
5677
|
+
return Parameters(objtype, self=obj)
|
|
5629
5678
|
|
|
5630
5679
|
|
|
5631
5680
|
class _PrivateNS:
|
|
@@ -5834,21 +5883,19 @@ class Parameterized(metaclass=ParameterizedMetaclass):
|
|
|
5834
5883
|
|
|
5835
5884
|
# Find parameters with default_factory through the class
|
|
5836
5885
|
# parameters to avoid making a copy.
|
|
5837
|
-
params_with_default_factory = [
|
|
5838
|
-
pname
|
|
5839
|
-
for pname, pobj in self.param._cls_parameters.items()
|
|
5840
|
-
if pname not in params
|
|
5841
|
-
and pobj.default_factory is not None
|
|
5842
|
-
]
|
|
5886
|
+
params_with_default_factory = type(self)._param__private.params_with_default_factory or []
|
|
5843
5887
|
# Set from default_factory once initialized so instance parameters
|
|
5844
5888
|
# are copied.
|
|
5845
5889
|
if params_with_default_factory:
|
|
5846
|
-
for pname in params_with_default_factory:
|
|
5847
|
-
|
|
5890
|
+
for pname, pobj in params_with_default_factory:
|
|
5891
|
+
if pname in params:
|
|
5892
|
+
continue
|
|
5848
5893
|
dfactory = pobj.default_factory
|
|
5849
5894
|
if dfactory is None:
|
|
5850
5895
|
continue
|
|
5851
5896
|
elif isinstance(dfactory, DefaultFactory):
|
|
5897
|
+
# DefaultFactory receives instance-level Parameter context.
|
|
5898
|
+
pobj = self.param[pname]
|
|
5852
5899
|
default_val = dfactory(cls=type(self), self=self, parameter=pobj)
|
|
5853
5900
|
else:
|
|
5854
5901
|
default_val = dfactory()
|
|
@@ -67,6 +67,7 @@ if t.TYPE_CHECKING:
|
|
|
67
67
|
from .parameterized import _ParameterKwargs
|
|
68
68
|
|
|
69
69
|
LT = t.TypeVar("LT")
|
|
70
|
+
CT = t.TypeVar("CT")
|
|
70
71
|
|
|
71
72
|
AT = t.TypeVar("AT", np.ndarray, np.ndarray | None)
|
|
72
73
|
DF = t.TypeVar("DF", pd.DataFrame, pd.DataFrame | None)
|
|
@@ -1638,11 +1639,11 @@ class NumericTuple(Tuple[_T]):
|
|
|
1638
1639
|
|
|
1639
1640
|
@t.overload
|
|
1640
1641
|
def __init__(
|
|
1641
|
-
self: NumericTuple[tuple[float, ...]
|
|
1642
|
+
self: NumericTuple[tuple[float, ...]],
|
|
1642
1643
|
default: tuple[float, ...] = (0.0, 0.0),
|
|
1643
1644
|
*,
|
|
1644
1645
|
length: int | None = None,
|
|
1645
|
-
allow_None: t.Literal[
|
|
1646
|
+
allow_None: t.Literal[False] = False,
|
|
1646
1647
|
doc: str | None = None,
|
|
1647
1648
|
label: str | None = None,
|
|
1648
1649
|
precedence: float | None = None,
|
|
@@ -1661,10 +1662,21 @@ class NumericTuple(Tuple[_T]):
|
|
|
1661
1662
|
@t.overload
|
|
1662
1663
|
def __init__(
|
|
1663
1664
|
self: NumericTuple[tuple[float, ...] | None],
|
|
1664
|
-
default: None =
|
|
1665
|
+
default: tuple[float, ...] | None = (0.0, 0.0),
|
|
1665
1666
|
*,
|
|
1666
1667
|
length: int | None = None,
|
|
1667
|
-
allow_None: t.Literal[
|
|
1668
|
+
allow_None: t.Literal[True] = True,
|
|
1669
|
+
**kwargs: Unpack[_ParameterKwargs]
|
|
1670
|
+
) -> None:
|
|
1671
|
+
...
|
|
1672
|
+
|
|
1673
|
+
@t.overload
|
|
1674
|
+
def __init__(
|
|
1675
|
+
self: NumericTuple[tuple[float, ...] | None],
|
|
1676
|
+
default: None,
|
|
1677
|
+
*,
|
|
1678
|
+
length: int | None = None,
|
|
1679
|
+
allow_None: bool = False,
|
|
1668
1680
|
**kwargs: Unpack[_ParameterKwargs]
|
|
1669
1681
|
) -> None:
|
|
1670
1682
|
...
|
|
@@ -2586,7 +2598,7 @@ class Selector(SelectorBase, _SignatureSelector[_T]):
|
|
|
2586
2598
|
object.__setattr__(self, 'check_on_set', check_on_set)
|
|
2587
2599
|
|
|
2588
2600
|
instantiate = params.pop("instantiate", Undefined)
|
|
2589
|
-
params["instantiate"] = False if instantiate is Undefined else instantiate
|
|
2601
|
+
params["instantiate"] = False if instantiate is Undefined else instantiate # pyrefly: ignore[bad-typed-dict-key]
|
|
2590
2602
|
super().__init__(default=default, **params)
|
|
2591
2603
|
# Required as Parameter sets allow_None=True if default is None
|
|
2592
2604
|
if allow_None is Undefined:
|
|
@@ -2915,10 +2927,10 @@ class ClassSelector(SelectorBase[_T]):
|
|
|
2915
2927
|
|
|
2916
2928
|
@t.overload
|
|
2917
2929
|
def __init__(
|
|
2918
|
-
self,
|
|
2930
|
+
self: ClassSelector[CT],
|
|
2919
2931
|
*,
|
|
2920
|
-
default:
|
|
2921
|
-
class_: type[
|
|
2932
|
+
default: CT,
|
|
2933
|
+
class_: type[CT],
|
|
2922
2934
|
is_instance: t.Literal[True] = True,
|
|
2923
2935
|
allow_None: t.Literal[False] = False,
|
|
2924
2936
|
doc: str | None = None,
|
|
@@ -2938,10 +2950,10 @@ class ClassSelector(SelectorBase[_T]):
|
|
|
2938
2950
|
|
|
2939
2951
|
@t.overload
|
|
2940
2952
|
def __init__(
|
|
2941
|
-
self,
|
|
2953
|
+
self: ClassSelector[CT | None],
|
|
2942
2954
|
*,
|
|
2943
2955
|
default: None = None,
|
|
2944
|
-
class_: type[
|
|
2956
|
+
class_: type[CT],
|
|
2945
2957
|
is_instance: t.Literal[True] = True,
|
|
2946
2958
|
allow_None: t.Literal[False] = False,
|
|
2947
2959
|
**kwargs: Unpack[_ParameterKwargs]
|
|
@@ -2950,10 +2962,10 @@ class ClassSelector(SelectorBase[_T]):
|
|
|
2950
2962
|
|
|
2951
2963
|
@t.overload
|
|
2952
2964
|
def __init__(
|
|
2953
|
-
self,
|
|
2965
|
+
self: ClassSelector[CT | None],
|
|
2954
2966
|
*,
|
|
2955
|
-
default:
|
|
2956
|
-
class_: type[
|
|
2967
|
+
default: CT | None = None,
|
|
2968
|
+
class_: type[CT],
|
|
2957
2969
|
is_instance: t.Literal[True] = True,
|
|
2958
2970
|
allow_None: t.Literal[True] = True,
|
|
2959
2971
|
**kwargs: Unpack[_ParameterKwargs]
|
|
@@ -2962,10 +2974,32 @@ class ClassSelector(SelectorBase[_T]):
|
|
|
2962
2974
|
|
|
2963
2975
|
@t.overload
|
|
2964
2976
|
def __init__(
|
|
2965
|
-
self,
|
|
2977
|
+
self: ClassSelector[t.Any],
|
|
2966
2978
|
*,
|
|
2967
|
-
default:
|
|
2968
|
-
class_:
|
|
2979
|
+
default: t.Any = None,
|
|
2980
|
+
class_: tuple[type, ...],
|
|
2981
|
+
is_instance: t.Literal[True] = True,
|
|
2982
|
+
allow_None: t.Literal[False] = False,
|
|
2983
|
+
**kwargs: Unpack[_ParameterKwargs]
|
|
2984
|
+
) -> None: ...
|
|
2985
|
+
|
|
2986
|
+
@t.overload
|
|
2987
|
+
def __init__(
|
|
2988
|
+
self: ClassSelector[t.Any],
|
|
2989
|
+
*,
|
|
2990
|
+
default: t.Any = None,
|
|
2991
|
+
class_: tuple[type, ...],
|
|
2992
|
+
is_instance: t.Literal[True] = True,
|
|
2993
|
+
allow_None: t.Literal[True] = True,
|
|
2994
|
+
**kwargs: Unpack[_ParameterKwargs]
|
|
2995
|
+
) -> None: ...
|
|
2996
|
+
|
|
2997
|
+
@t.overload
|
|
2998
|
+
def __init__(
|
|
2999
|
+
self: ClassSelector[type[CT]],
|
|
3000
|
+
*,
|
|
3001
|
+
default: type[CT],
|
|
3002
|
+
class_: type[CT],
|
|
2969
3003
|
is_instance: t.Literal[False],
|
|
2970
3004
|
allow_None: t.Literal[False] = False,
|
|
2971
3005
|
**kwargs: Unpack[_ParameterKwargs]
|
|
@@ -2974,10 +3008,10 @@ class ClassSelector(SelectorBase[_T]):
|
|
|
2974
3008
|
|
|
2975
3009
|
@t.overload
|
|
2976
3010
|
def __init__(
|
|
2977
|
-
self,
|
|
3011
|
+
self: ClassSelector[type[CT] | None],
|
|
2978
3012
|
*,
|
|
2979
3013
|
default: None = None,
|
|
2980
|
-
class_: type[
|
|
3014
|
+
class_: type[CT] | tuple[type[CT], ...],
|
|
2981
3015
|
is_instance: t.Literal[False],
|
|
2982
3016
|
allow_None: t.Literal[False] = False,
|
|
2983
3017
|
**kwargs: Unpack[_ParameterKwargs]
|
|
@@ -2986,16 +3020,27 @@ class ClassSelector(SelectorBase[_T]):
|
|
|
2986
3020
|
|
|
2987
3021
|
@t.overload
|
|
2988
3022
|
def __init__(
|
|
2989
|
-
self,
|
|
3023
|
+
self: ClassSelector[type[CT] | None],
|
|
2990
3024
|
*,
|
|
2991
|
-
default: type[
|
|
2992
|
-
class_: type[
|
|
3025
|
+
default: type[CT] | None = None,
|
|
3026
|
+
class_: type[CT] | tuple[type[CT], ...],
|
|
2993
3027
|
is_instance: t.Literal[False],
|
|
2994
3028
|
allow_None: t.Literal[True] = True,
|
|
2995
3029
|
**kwargs: Unpack[_ParameterKwargs]
|
|
2996
3030
|
) -> None:
|
|
2997
3031
|
...
|
|
2998
3032
|
|
|
3033
|
+
@t.overload
|
|
3034
|
+
def __init__(
|
|
3035
|
+
self: ClassSelector[t.Any],
|
|
3036
|
+
*,
|
|
3037
|
+
default: t.Any = None,
|
|
3038
|
+
class_: tuple[type, ...],
|
|
3039
|
+
is_instance: t.Literal[False] = False,
|
|
3040
|
+
allow_None: t.Literal[False] = False,
|
|
3041
|
+
**kwargs: Unpack[_ParameterKwargs]
|
|
3042
|
+
) -> None: ...
|
|
3043
|
+
|
|
2999
3044
|
def __init__(
|
|
3000
3045
|
self, *,
|
|
3001
3046
|
class_: type | tuple[type, ...] = t.cast("type | tuple[type, ...]", Undefined), # pyrefly: ignore[bad-argument-type]
|
|
@@ -3158,7 +3203,7 @@ class Array(ClassSelector["AT"]):
|
|
|
3158
3203
|
import numpy
|
|
3159
3204
|
super().__init__( # type: ignore[misc, call-overload]
|
|
3160
3205
|
default=default, # type: ignore[arg-type]
|
|
3161
|
-
class_=numpy.ndarray,
|
|
3206
|
+
class_=numpy.ndarray, # type: ignore[arg-type]
|
|
3162
3207
|
is_instance=True,
|
|
3163
3208
|
allow_None=allow_None, # type: ignore[arg-type]
|
|
3164
3209
|
**params, # type: ignore[arg-type]
|
|
@@ -3471,7 +3516,7 @@ class List(Parameter[_T]):
|
|
|
3471
3516
|
self: List[list[LT]],
|
|
3472
3517
|
default: list[LT] = [],
|
|
3473
3518
|
*,
|
|
3474
|
-
item_type: type[LT] | tuple[type[LT], ...]
|
|
3519
|
+
item_type: type[LT] | tuple[type[LT], ...] = (),
|
|
3475
3520
|
bounds: tuple[int, int | None] | None = (0, None),
|
|
3476
3521
|
is_instance: bool = True,
|
|
3477
3522
|
allow_None: t.Literal[False] = False,
|
|
@@ -3495,7 +3540,7 @@ class List(Parameter[_T]):
|
|
|
3495
3540
|
self: List[list[LT] | None],
|
|
3496
3541
|
default: list[LT] | None = None,
|
|
3497
3542
|
*,
|
|
3498
|
-
item_type: type[LT] | tuple[type[LT], ...]
|
|
3543
|
+
item_type: type[LT] | tuple[type[LT], ...] = (),
|
|
3499
3544
|
allow_None: t.Literal[True] = True,
|
|
3500
3545
|
**kwargs: Unpack[_ParameterKwargs]
|
|
3501
3546
|
) -> None:
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
import abc
|
|
3
3
|
import inspect
|
|
4
4
|
import re
|
|
5
|
+
import sys
|
|
5
6
|
import unittest
|
|
6
7
|
import warnings
|
|
8
|
+
import weakref
|
|
7
9
|
|
|
8
10
|
import param
|
|
9
11
|
import numbergen
|
|
@@ -1981,3 +1983,22 @@ def test_abc_basic_checks():
|
|
|
1981
1983
|
assert gc.l == [10]
|
|
1982
1984
|
gc.x += 1
|
|
1983
1985
|
assert gc.l == [10, 11]
|
|
1986
|
+
|
|
1987
|
+
|
|
1988
|
+
@pytest.mark.skipif(sys.implementation.name == "pypy", reason='Works differently on PyPy')
|
|
1989
|
+
def test_no_param_namespace_cycle():
|
|
1990
|
+
# Accessing .param on an instance must not create a reference cycle.
|
|
1991
|
+
# A cycle (obj -> obj.__dict__['_param__parameters'] -> Parameters.self -> obj)
|
|
1992
|
+
# would prevent CPython's reference-counting from immediately freeing the
|
|
1993
|
+
# object, breaking weakref-based cleanup used by libraries like HoloViews.
|
|
1994
|
+
class P(param.Parameterized):
|
|
1995
|
+
x = param.Number(1)
|
|
1996
|
+
|
|
1997
|
+
freed = []
|
|
1998
|
+
obj = P()
|
|
1999
|
+
ref = weakref.ref(obj, lambda _: freed.append(True)) # noqa: F841
|
|
2000
|
+
|
|
2001
|
+
_ = obj.param.values() # access .param to trigger any caching
|
|
2002
|
+
|
|
2003
|
+
del obj
|
|
2004
|
+
assert freed, "Parameterized instance not freed immediately — likely a reference cycle via .param"
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|