param 2.3.2rc1__tar.gz → 2.3.3b0__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.3.2rc1 → param-2.3.3b0}/PKG-INFO +1 -1
- param-2.3.3b0/param/_version.py +24 -0
- {param-2.3.2rc1 → param-2.3.3b0}/param/reactive.py +41 -6
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testreactive.py +66 -0
- param-2.3.2rc1/param/_version.py +0 -34
- {param-2.3.2rc1 → param-2.3.3b0}/.gitignore +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/LICENSE.txt +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/README.md +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/numbergen/__init__.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/param/__init__.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/param/_utils.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/param/depends.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/param/display.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/param/ipython.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/param/parameterized.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/param/parameters.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/param/serializer.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/param/version.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/pyproject.toml +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/__init__.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/conftest.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testaddparameter.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testbind.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testbooleanparam.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testbytesparam.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testcalendardateparam.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testcalendardaterangeparam.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testcallable.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testclassselector.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testcolorparameter.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testcomparator.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testcompositeparams.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testcustomparam.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testdateparam.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testdaterangeparam.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testdefaultfactory.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testdefaults.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testdeprecations.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testdynamicparams.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testfiledeserialization.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testfileselector.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testimports.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testipythonmagic.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testjsonserialization.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testlist.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testlistselector.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testmultifileselector.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testnumbergen.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testnumberparameter.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testnumpy.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testobjectselector.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testpandas.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testparamdepends.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testparameter.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testparameterizedobject.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testparameterizedrepr.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testparamoutput.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testparamunion.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testpathparam.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testpickle.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testrangeparameter.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testrefs.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testreprhtml.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testselector.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testsignatures.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/teststringparam.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testtimedependent.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testtupleparam.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testutils.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testversion.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/testwatch.py +0 -0
- {param-2.3.2rc1 → param-2.3.3b0}/tests/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: param
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.3b0
|
|
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
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '2.3.3b0'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 3, 3, 'b0')
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = None
|
|
@@ -1436,7 +1436,7 @@ class rx:
|
|
|
1436
1436
|
|
|
1437
1437
|
def __init__(
|
|
1438
1438
|
self, obj=None, operation=None, fn=None, depth=0, method=None, prev=None,
|
|
1439
|
-
_shared_obj=None, _current=None, _wrapper=None, **kwargs
|
|
1439
|
+
_shared_obj=None, _current=None, _wrapper=None, _shared=None, **kwargs
|
|
1440
1440
|
):
|
|
1441
1441
|
# _init is used to prevent to __getattribute__ to execute its
|
|
1442
1442
|
# specialized code.
|
|
@@ -1458,6 +1458,11 @@ class rx:
|
|
|
1458
1458
|
self._current_task = None
|
|
1459
1459
|
self._error_state = None
|
|
1460
1460
|
self._current_ = _current
|
|
1461
|
+
# _shared is used for branching rx pipelines where we clone the input.
|
|
1462
|
+
# Here we store the original shared input, which makes it possible to
|
|
1463
|
+
# cache the input value as long as the shared instance does not store
|
|
1464
|
+
# a diverging _method accessor.
|
|
1465
|
+
self._shared = _shared
|
|
1461
1466
|
if isinstance(obj, rx) and not prev:
|
|
1462
1467
|
self._prev = obj
|
|
1463
1468
|
else:
|
|
@@ -1529,6 +1534,17 @@ class rx:
|
|
|
1529
1534
|
root._dirty_obj = False
|
|
1530
1535
|
return self._shared_obj[0]
|
|
1531
1536
|
|
|
1537
|
+
@property
|
|
1538
|
+
def _is_async(self) -> bool:
|
|
1539
|
+
if not self._operation:
|
|
1540
|
+
return False
|
|
1541
|
+
fn = self._operation["fn"]
|
|
1542
|
+
return (
|
|
1543
|
+
inspect.iscoroutinefunction(fn) or
|
|
1544
|
+
inspect.isasyncgenfunction(fn) or
|
|
1545
|
+
inspect.isgeneratorfunction(fn)
|
|
1546
|
+
)
|
|
1547
|
+
|
|
1532
1548
|
@_obj.setter
|
|
1533
1549
|
def _obj(self, obj):
|
|
1534
1550
|
if self._shared_obj is None:
|
|
@@ -1632,10 +1648,15 @@ class rx:
|
|
|
1632
1648
|
self._root._dirty_obj = True
|
|
1633
1649
|
self._error_state = None
|
|
1634
1650
|
|
|
1635
|
-
async def _resolve_async(self, obj):
|
|
1651
|
+
async def _resolve_async(self, obj = None):
|
|
1636
1652
|
import asyncio
|
|
1637
1653
|
self._current_task = task = asyncio.current_task()
|
|
1638
|
-
if
|
|
1654
|
+
if obj is None:
|
|
1655
|
+
if self._shared._current_task:
|
|
1656
|
+
await self._shared._current_task
|
|
1657
|
+
self._current_ = self._shared.rx.value
|
|
1658
|
+
self._trigger.param.trigger('value')
|
|
1659
|
+
elif inspect.isasyncgen(obj):
|
|
1639
1660
|
async for val in obj:
|
|
1640
1661
|
if self._current_task is not task:
|
|
1641
1662
|
break
|
|
@@ -1647,7 +1668,7 @@ class rx:
|
|
|
1647
1668
|
self._current_ = value
|
|
1648
1669
|
self._trigger.param.trigger('value')
|
|
1649
1670
|
|
|
1650
|
-
def _lazy_resolve(self, obj):
|
|
1671
|
+
def _lazy_resolve(self, obj = None):
|
|
1651
1672
|
from .parameterized import async_executor
|
|
1652
1673
|
if inspect.isgenerator(obj):
|
|
1653
1674
|
obj = _to_async_gen(obj)
|
|
@@ -1662,10 +1683,24 @@ class rx:
|
|
|
1662
1683
|
if obj is Skip or obj is Undefined:
|
|
1663
1684
|
self._current_ = Undefined
|
|
1664
1685
|
raise Skip
|
|
1686
|
+
elif (
|
|
1687
|
+
self._shared is not None and
|
|
1688
|
+
self._method is None and
|
|
1689
|
+
self._shared._method is None
|
|
1690
|
+
):
|
|
1691
|
+
# If this rx is cloned from an shared input then we make use
|
|
1692
|
+
# of the shared.rx.value to ensure branching pipelines do
|
|
1693
|
+
# not have to recompute the inputs multiple times.
|
|
1694
|
+
if self._is_async:
|
|
1695
|
+
self._shared.rx.value # trigger async resolve
|
|
1696
|
+
self._lazy_resolve()
|
|
1697
|
+
else:
|
|
1698
|
+
self._current_ = self._shared.rx.value
|
|
1699
|
+
raise Skip
|
|
1665
1700
|
operation = self._operation
|
|
1666
1701
|
if operation:
|
|
1667
1702
|
obj = self._eval_operation(obj, operation)
|
|
1668
|
-
if
|
|
1703
|
+
if self._is_async:
|
|
1669
1704
|
self._lazy_resolve(obj)
|
|
1670
1705
|
obj = Skip
|
|
1671
1706
|
if obj is Skip:
|
|
@@ -1723,7 +1758,7 @@ class rx:
|
|
|
1723
1758
|
if copy:
|
|
1724
1759
|
kwargs = dict(
|
|
1725
1760
|
self._kwargs, _current=self._current, method=self._method,
|
|
1726
|
-
prev=self._prev, **kwargs
|
|
1761
|
+
prev=self._prev, _shared=self, **kwargs
|
|
1727
1762
|
)
|
|
1728
1763
|
else:
|
|
1729
1764
|
kwargs = dict(prev=self, **dict(self._kwargs, **kwargs))
|
|
@@ -775,3 +775,69 @@ def test_reactive_set_value_attributeerror():
|
|
|
775
775
|
x = rx(1)
|
|
776
776
|
with pytest.raises(AttributeError, match="'rx' has no attribute 'value'"):
|
|
777
777
|
x.value = 1
|
|
778
|
+
|
|
779
|
+
def test_shared_rx_only_triggers_once():
|
|
780
|
+
call_count = 0
|
|
781
|
+
|
|
782
|
+
class Model(param.Parameterized):
|
|
783
|
+
a = param.Number(1.0)
|
|
784
|
+
|
|
785
|
+
model = Model()
|
|
786
|
+
|
|
787
|
+
def expensive_compute(a):
|
|
788
|
+
nonlocal call_count
|
|
789
|
+
call_count += 1
|
|
790
|
+
return {"x": a + 1, "y": a * 2}
|
|
791
|
+
|
|
792
|
+
shared = rx(expensive_compute)(model.param.a)
|
|
793
|
+
|
|
794
|
+
x_rx = shared.rx.pipe(lambda d: d["x"])
|
|
795
|
+
y_rx = shared.rx.pipe(lambda d: d["y"])
|
|
796
|
+
|
|
797
|
+
x_rx.rx.value
|
|
798
|
+
y_rx.rx.value
|
|
799
|
+
|
|
800
|
+
assert call_count == 1
|
|
801
|
+
|
|
802
|
+
model.a = 2.0
|
|
803
|
+
|
|
804
|
+
x_rx.rx.value
|
|
805
|
+
y_rx.rx.value
|
|
806
|
+
|
|
807
|
+
assert call_count == 2
|
|
808
|
+
|
|
809
|
+
|
|
810
|
+
async def test_async_shared_rx_only_triggers_once():
|
|
811
|
+
call_count = 0
|
|
812
|
+
|
|
813
|
+
class Model(param.Parameterized):
|
|
814
|
+
a = param.Number(1.0)
|
|
815
|
+
|
|
816
|
+
model = Model()
|
|
817
|
+
|
|
818
|
+
async def expensive_compute(a):
|
|
819
|
+
nonlocal call_count
|
|
820
|
+
call_count += 1
|
|
821
|
+
return {"x": a + 1, "y": a * 2}
|
|
822
|
+
|
|
823
|
+
shared = model.param.a.rx.pipe(expensive_compute)
|
|
824
|
+
|
|
825
|
+
x_rx = shared.rx.pipe(lambda d: d["x"])
|
|
826
|
+
y_rx = shared.rx.pipe(lambda d: d["y"])
|
|
827
|
+
|
|
828
|
+
x_rx.rx.value
|
|
829
|
+
y_rx.rx.value
|
|
830
|
+
|
|
831
|
+
await async_wait_until(lambda: call_count == 1)
|
|
832
|
+
|
|
833
|
+
model.a = 2.0
|
|
834
|
+
|
|
835
|
+
x_rx.rx.value
|
|
836
|
+
y_rx.rx.value
|
|
837
|
+
|
|
838
|
+
await async_wait_until(lambda: call_count == 2)
|
|
839
|
+
|
|
840
|
+
assert x_rx.rx.value == 3
|
|
841
|
+
assert y_rx.rx.value == 4
|
|
842
|
+
|
|
843
|
+
assert call_count == 2
|
param-2.3.2rc1/param/_version.py
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# file generated by setuptools-scm
|
|
2
|
-
# don't change, don't track in version control
|
|
3
|
-
|
|
4
|
-
__all__ = [
|
|
5
|
-
"__version__",
|
|
6
|
-
"__version_tuple__",
|
|
7
|
-
"version",
|
|
8
|
-
"version_tuple",
|
|
9
|
-
"__commit_id__",
|
|
10
|
-
"commit_id",
|
|
11
|
-
]
|
|
12
|
-
|
|
13
|
-
TYPE_CHECKING = False
|
|
14
|
-
if TYPE_CHECKING:
|
|
15
|
-
from typing import Tuple
|
|
16
|
-
from typing import Union
|
|
17
|
-
|
|
18
|
-
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
-
COMMIT_ID = Union[str, None]
|
|
20
|
-
else:
|
|
21
|
-
VERSION_TUPLE = object
|
|
22
|
-
COMMIT_ID = object
|
|
23
|
-
|
|
24
|
-
version: str
|
|
25
|
-
__version__: str
|
|
26
|
-
__version_tuple__: VERSION_TUPLE
|
|
27
|
-
version_tuple: VERSION_TUPLE
|
|
28
|
-
commit_id: COMMIT_ID
|
|
29
|
-
__commit_id__: COMMIT_ID
|
|
30
|
-
|
|
31
|
-
__version__ = version = '2.3.2rc1'
|
|
32
|
-
__version_tuple__ = version_tuple = (2, 3, 2, 'rc1')
|
|
33
|
-
|
|
34
|
-
__commit_id__ = commit_id = None
|
|
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
|
|
File without changes
|