My app is constituted of a main and several auxiliary modules. In the main file, an App object is instantiated.
In the main file, pn.state.served is True, but it’s also True within the scope of the App object only if the class is defined within the same module. If it’s imported, then it’s False. Note that the pn.state object does point to the same location in memory regardless.
In other words this prints True:
import panel as pn
class Something:
def __init__(self):
print(pn.state.served)
if pn.state.served:
Something()
But this prints False:
import panel as pn
from other_module import Something
if pn.state.served:
Something()
This is annoying for test purposes, because there are some commands that I can’t do outside of a server context (e.g. using pn.state.notifications) so I need to know if I have to avoid them.
I don’t know if there are ways to do this other than passing pn.state.served to the App constructor and all other objects downwards.
I see that .served is a property so that explains why it gives different results based on the module from which it is called.
There must be a reason why it’s not a standard attribute of the _state class, but that way it would be set once and for all (allowing for its use everywhere).
As for the pn.state methods, yes I did not realise that the only reason why pn.state.notifications did not work in my test setting was that I did not set pn.extension('notifications')… Thanks again!
There is a good reason for this, which is that the served property only ever makes sense in the context of the served application module. Any module you import inside an application will only ever be evaluated once (on the first import) and any subsequent import will simply load the cached module. Therefore there is no meaning to pn.state.served outside the context of the application module.
I realize that session contexts and how application modules vs. imported modules work is a major gap in our documentation (as well as Bokeh’s). Once you understand that the application modules are created per session but anything you import is effectively global then that starts giving you a deeper insight into how session state vs global state works. We will need a proper background/explanation section on this.
My main question is what the Something() in your mock code is actually doing? My suspicion is that whatever it is likely would not have worked correctly and the fact that it didn’t saved you from doing something that may have worked in testing but would break in production because the second time the app is loaded Something() would not have been re-evaluated.
It is quite clear when working with bokeh and panel that the app module is per-session while other modules are imported once and shared across sessions. For instance, that allowed for the use of a shared cache between users before the built-in panel cache feature was added.
To answer your question, in my case the Something() is the actual app object, and in turn it imports viewable components from other modules. In one of these modules I have to access pn.state.curdoc.session_context (to read cookies) but that cannot work in a test setting. One way to go is to check whether curdoc is None before proceeding, but it would be cleaner to use pn.state.served.
Anyway, even if a module is imported only once, if the pn.state.served statement is not put at module-level but within the scope of a function/object (which is the case for me), it will be evaluated each time that function/object is used. In this regard, maybe having state.served as a standard attribute set once and for all at session initialisation would make sense.