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.
Files changed (72) hide show
  1. {param-2.3.2rc1 → param-2.3.3b0}/PKG-INFO +1 -1
  2. param-2.3.3b0/param/_version.py +24 -0
  3. {param-2.3.2rc1 → param-2.3.3b0}/param/reactive.py +41 -6
  4. {param-2.3.2rc1 → param-2.3.3b0}/tests/testreactive.py +66 -0
  5. param-2.3.2rc1/param/_version.py +0 -34
  6. {param-2.3.2rc1 → param-2.3.3b0}/.gitignore +0 -0
  7. {param-2.3.2rc1 → param-2.3.3b0}/LICENSE.txt +0 -0
  8. {param-2.3.2rc1 → param-2.3.3b0}/README.md +0 -0
  9. {param-2.3.2rc1 → param-2.3.3b0}/numbergen/__init__.py +0 -0
  10. {param-2.3.2rc1 → param-2.3.3b0}/param/__init__.py +0 -0
  11. {param-2.3.2rc1 → param-2.3.3b0}/param/_utils.py +0 -0
  12. {param-2.3.2rc1 → param-2.3.3b0}/param/depends.py +0 -0
  13. {param-2.3.2rc1 → param-2.3.3b0}/param/display.py +0 -0
  14. {param-2.3.2rc1 → param-2.3.3b0}/param/ipython.py +0 -0
  15. {param-2.3.2rc1 → param-2.3.3b0}/param/parameterized.py +0 -0
  16. {param-2.3.2rc1 → param-2.3.3b0}/param/parameters.py +0 -0
  17. {param-2.3.2rc1 → param-2.3.3b0}/param/serializer.py +0 -0
  18. {param-2.3.2rc1 → param-2.3.3b0}/param/version.py +0 -0
  19. {param-2.3.2rc1 → param-2.3.3b0}/pyproject.toml +0 -0
  20. {param-2.3.2rc1 → param-2.3.3b0}/tests/__init__.py +0 -0
  21. {param-2.3.2rc1 → param-2.3.3b0}/tests/conftest.py +0 -0
  22. {param-2.3.2rc1 → param-2.3.3b0}/tests/testaddparameter.py +0 -0
  23. {param-2.3.2rc1 → param-2.3.3b0}/tests/testbind.py +0 -0
  24. {param-2.3.2rc1 → param-2.3.3b0}/tests/testbooleanparam.py +0 -0
  25. {param-2.3.2rc1 → param-2.3.3b0}/tests/testbytesparam.py +0 -0
  26. {param-2.3.2rc1 → param-2.3.3b0}/tests/testcalendardateparam.py +0 -0
  27. {param-2.3.2rc1 → param-2.3.3b0}/tests/testcalendardaterangeparam.py +0 -0
  28. {param-2.3.2rc1 → param-2.3.3b0}/tests/testcallable.py +0 -0
  29. {param-2.3.2rc1 → param-2.3.3b0}/tests/testclassselector.py +0 -0
  30. {param-2.3.2rc1 → param-2.3.3b0}/tests/testcolorparameter.py +0 -0
  31. {param-2.3.2rc1 → param-2.3.3b0}/tests/testcomparator.py +0 -0
  32. {param-2.3.2rc1 → param-2.3.3b0}/tests/testcompositeparams.py +0 -0
  33. {param-2.3.2rc1 → param-2.3.3b0}/tests/testcustomparam.py +0 -0
  34. {param-2.3.2rc1 → param-2.3.3b0}/tests/testdateparam.py +0 -0
  35. {param-2.3.2rc1 → param-2.3.3b0}/tests/testdaterangeparam.py +0 -0
  36. {param-2.3.2rc1 → param-2.3.3b0}/tests/testdefaultfactory.py +0 -0
  37. {param-2.3.2rc1 → param-2.3.3b0}/tests/testdefaults.py +0 -0
  38. {param-2.3.2rc1 → param-2.3.3b0}/tests/testdeprecations.py +0 -0
  39. {param-2.3.2rc1 → param-2.3.3b0}/tests/testdynamicparams.py +0 -0
  40. {param-2.3.2rc1 → param-2.3.3b0}/tests/testfiledeserialization.py +0 -0
  41. {param-2.3.2rc1 → param-2.3.3b0}/tests/testfileselector.py +0 -0
  42. {param-2.3.2rc1 → param-2.3.3b0}/tests/testimports.py +0 -0
  43. {param-2.3.2rc1 → param-2.3.3b0}/tests/testipythonmagic.py +0 -0
  44. {param-2.3.2rc1 → param-2.3.3b0}/tests/testjsonserialization.py +0 -0
  45. {param-2.3.2rc1 → param-2.3.3b0}/tests/testlist.py +0 -0
  46. {param-2.3.2rc1 → param-2.3.3b0}/tests/testlistselector.py +0 -0
  47. {param-2.3.2rc1 → param-2.3.3b0}/tests/testmultifileselector.py +0 -0
  48. {param-2.3.2rc1 → param-2.3.3b0}/tests/testnumbergen.py +0 -0
  49. {param-2.3.2rc1 → param-2.3.3b0}/tests/testnumberparameter.py +0 -0
  50. {param-2.3.2rc1 → param-2.3.3b0}/tests/testnumpy.py +0 -0
  51. {param-2.3.2rc1 → param-2.3.3b0}/tests/testobjectselector.py +0 -0
  52. {param-2.3.2rc1 → param-2.3.3b0}/tests/testpandas.py +0 -0
  53. {param-2.3.2rc1 → param-2.3.3b0}/tests/testparamdepends.py +0 -0
  54. {param-2.3.2rc1 → param-2.3.3b0}/tests/testparameter.py +0 -0
  55. {param-2.3.2rc1 → param-2.3.3b0}/tests/testparameterizedobject.py +0 -0
  56. {param-2.3.2rc1 → param-2.3.3b0}/tests/testparameterizedrepr.py +0 -0
  57. {param-2.3.2rc1 → param-2.3.3b0}/tests/testparamoutput.py +0 -0
  58. {param-2.3.2rc1 → param-2.3.3b0}/tests/testparamunion.py +0 -0
  59. {param-2.3.2rc1 → param-2.3.3b0}/tests/testpathparam.py +0 -0
  60. {param-2.3.2rc1 → param-2.3.3b0}/tests/testpickle.py +0 -0
  61. {param-2.3.2rc1 → param-2.3.3b0}/tests/testrangeparameter.py +0 -0
  62. {param-2.3.2rc1 → param-2.3.3b0}/tests/testrefs.py +0 -0
  63. {param-2.3.2rc1 → param-2.3.3b0}/tests/testreprhtml.py +0 -0
  64. {param-2.3.2rc1 → param-2.3.3b0}/tests/testselector.py +0 -0
  65. {param-2.3.2rc1 → param-2.3.3b0}/tests/testsignatures.py +0 -0
  66. {param-2.3.2rc1 → param-2.3.3b0}/tests/teststringparam.py +0 -0
  67. {param-2.3.2rc1 → param-2.3.3b0}/tests/testtimedependent.py +0 -0
  68. {param-2.3.2rc1 → param-2.3.3b0}/tests/testtupleparam.py +0 -0
  69. {param-2.3.2rc1 → param-2.3.3b0}/tests/testutils.py +0 -0
  70. {param-2.3.2rc1 → param-2.3.3b0}/tests/testversion.py +0 -0
  71. {param-2.3.2rc1 → param-2.3.3b0}/tests/testwatch.py +0 -0
  72. {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.2rc1
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 inspect.isasyncgen(obj):
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 inspect.isasyncgen(obj) or inspect.iscoroutine(obj) or inspect.isgenerator(obj):
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
@@ -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