holoviz / param

Param: Make your Python code clearer and more reliable by declaring Parameters
https://param.holoviz.org
BSD 3-Clause "New" or "Revised" License
410 stars 69 forks source link

Initialization changes constant attribute. #931

Open LinuxIsCool opened 2 months ago

LinuxIsCool commented 2 months ago

Thanks for contacting us! Please read and follow these instructions carefully, then delete this introductory text to keep your issue easy to read. Note that the issue tracker is NOT the place for usage questions and technical assistance; post those at Discourse instead. Issues without the required information below may be closed immediately.

ALL software version info

panel==1.4.0 param==2.1.0 Python 3.10.12

Description of expected behavior and the observed behavior

Expecting normal initialization. Unfortunately, constant is being set to False on my parameter.

I would expect invariant_coef to remain constant.

Complete, minimal, self-contained example code that reproduces the issue

import param as pm
import panel as pn
pn.extension()

class BondingCurve(pm.Parameterized):
    supply = pm.Number(80)
    reserve = pm.Number(40)
    kappa = pm.Number(2)
    invariant_coef = pm.Number(constant=True)
    price = pm.Number(constant=True)

    # def __init__(self, **params):
    #     super().__init__(**params)
    #     self.set_invariant_coef()

    @pm.depends(on_init=True, watch=True)
    def set_invariant_coef(self):
        with pm.edit_constant(self):
            self.invariant_coef = self.supply ** self.kappa / self.reserve

bc = BondingCurve()

pn.panel(bc)

bc.param['invariant_coef'].constant

False

image

hoxbro commented 2 months ago

This context manager seems to work not sure about what 'existing' does

import param as pm
import panel as pn
from contextlib import contextmanager

@contextmanager
def edit_constant(parameterized):
    """
    Temporarily set parameters on Parameterized object to constant=False
    to allow editing them.
    """
    params = parameterized.param.objects().values()  # changed from: 
    # params = parameterized.param.objects('existing').values()
    constants = [p.constant for p in params]
    for p in params:
        p.constant = False
    try:
        yield
    finally:
        for p, const in zip(params, constants):
            p.constant = const

class BondingCurve(pm.Parameterized):
    price = pm.Number(constant=True)

    @pm.depends(on_init=True, watch=True)
    def set_ex(self):
        with edit_constant(self):
            self.price = 1

bc = BondingCurve()

bc.param.price.constant, bc.price
LinuxIsCool commented 2 months ago

Hi is this a bug in the library?

Again, I'm trying to use constants and edit_constant but am having this bug with the library.

philippjfr commented 2 months ago

That does look like a bug, yes.