panel icon indicating copy to clipboard operation
panel copied to clipboard

Make it easier to use pn.state.as_cached by supporting unnamed arguments

Open MarcSkovMadsen opened this issue 2 years ago • 7 comments

When trying to cache (via as_cached) a function that you normally use with unnamed arguments its friction you have to spend time on looking up the name of the argument.

Example:

Normally I do pd.read_csv("my_file.csv") and similar. Thus i would expect to be able to do

pn.state.as_cached("data", pd.read_csv, "my_file.csv")

But this raises

TypeError: unsupported operand type(s) for +: 'float' and 'str'
Traceback (most recent call last):
  File "C:\repos\private\panel\.venv\lib\site-packages\bokeh\application\handlers\code_runner.py", line 231, in run
    exec(self._code, module.__dict__)
  File "C:\repos\private\panel\script.py", line 6, in <module>
    data = pn.state.as_cached("data", pd.read_csv, "tabulator.csv")
  File "c:\repos\private\panel\panel\io\state.py", line 453, in as_cached
    new_expiry = time.monotonic() + ttl if ttl else None
TypeError: unsupported operand type(s) for +: 'float' and 'str'

Thus i have to lookup the name of the argument filepath_or_buffer which I never use otherwise.

Please change to the function signature

from

def as_cached(self, key: str, fn: Callable[[], T], ttl: int = None, **kwargs) -> T:
def as_cached(self, key: str, fn: Callable[[], T], *args, ttl: int = None, **kwargs) -> T:

MarcSkovMadsen avatar Mar 27 '23 07:03 MarcSkovMadsen

This will probably need a transition period. What you suggest breaks backward compatibility.

Function signature during the transition period could require ttl to be a keyword: def as_cached(self, key: str, fn: Callable[[], T], *, ttl: int = None, **kwargs) -> T:

hoxbro avatar Mar 27 '23 07:03 hoxbro

I would suggest making the change in connecting with 1.0. There we can fix anything that should have been different.

MarcSkovMadsen avatar Mar 27 '23 07:03 MarcSkovMadsen

You are probably right @Hoxbro and I'm too hasty 👍

MarcSkovMadsen avatar Mar 27 '23 08:03 MarcSkovMadsen

We really should review the API and use keyword only args where possible.

philippjfr avatar Apr 03 '23 16:04 philippjfr

Yes. This is such a time waster. Everytime I want to use pd.read_csv and as_cached I have to look up that the argument is called filepath_or_buffer. No body writes that. No body remembers that. It just makes the code harder to read.

MarcSkovMadsen avatar Dec 01 '23 06:12 MarcSkovMadsen

I was also confused by this, because according to the docs: "If provided, the args and kwargs will also be hashed making it easy to cache (or memoize) on the arguments to the function:"

def load_data(*args, **kwargs):
    return ... # Load some data

data = pn.state.as_cached('data', load_data, *args, **kwargs)

Which seems to imply that you can pass positional arguments or *args and **kwargs directly after the function, but in reality, everything has to be passed as keyword arguments (named parameters).

OSuwaidi avatar Apr 10 '25 11:04 OSuwaidi

Also, currently fn requires a Callable[[], T] which is a function that accepts no arg/kwargs. I believe it should be updated to Callable[..., T] (ellipsis literal) to allow any arbitrary args/kwargs to be passed to the given function.

Didn't think this was worth creating a new issue, but let me know if I should.

jurriaanpro avatar May 21 '25 12:05 jurriaanpro