-
-
Notifications
You must be signed in to change notification settings - Fork 519
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for - middleware for component level interactions + custom name for logging purposes #5273
base: main
Are you sure you want to change the base?
Add support for - middleware for component level interactions + custom name for logging purposes #5273
Conversation
Codecov Report
@@ Coverage Diff @@
## main #5273 +/- ##
===========================================
+ Coverage 38.60% 72.28% +33.68%
===========================================
Files 290 292 +2
Lines 42318 42380 +62
===========================================
+ Hits 16337 30635 +14298
+ Misses 25981 11745 -14236
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 222 files with indirect coverage changes 📣 Codecov offers a browser extension for seamless coverage viewing on GitHub. Try it in Chrome or Firefox today! |
@philippjfr let me know what else would be required here e.g. tests, more documentation etc. Please point to any references. Thanks! |
@philippjfr please let me know any review comments here. Thanks!! |
Hi, @philippjfr @MarcSkovMadsen please add your review comments / thoughts here so we can push these changes. Thanks! |
I'll do a quick review shortly but also wanted to hear from @maximlt since he's been thinking about using this for some logging. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @nishikantparmariam and sorry for the late reply. I have some interest in some similar functionality so here are some questions:
- would you have an example use case for watching property changes?
- do you think the
preprocess
/postprocess
model is going to be convenient enough to for instance time how long it took to process an event? I see for instance that FastAPI has a different model for setting up middlewares so just checking we're going down the right path
(https://fastapi.tiangolo.com/tutorial/middleware/#create-a-middleware)
I'm going to do more testing on a larger app that would require some middleware logging and will report back when done.
Hi @maximlt,
Yes, there are many e.g. I want to log if user changed tab of
Thanks for pointing this out! Yes, it should be convenient. Here is how one may write a timing middleware:class TimingMiddleware(PropertyChangeEventMiddleware):
def __init__(self):
"""Do any initialization"""
def preprocess(self, syncable, doc, events):
self.start_time = time.time()
self.syncable = syncable # Save for postprocess
def postprocess(self):
process_time = time.time() - self.start_time
# Do something with self.syncable now
pn.state.add_property_change_event_middleware(TimingMiddleware()) I also explored django and expressjs middlewares. Then, I realized that in pre/postprocess model, for more advanced cases there is an issue: If one wants to run pre of middleware1 before pre of middleware2, but want that post of middleware1 runs after post of middleware2. See ExplanationPreprocess/postprocess model (current implementation):
Whereas the other models e.g. FastAPI, django works like this (Reference) -
To fix this in pre/postprocesss model, it seems correct thing would be to run for bokeh_event_middleware in state._bokeh_event_middlewares[::-1]:
bokeh_event_middleware.postprocess() And, we should mention in the docs that postprocess of current middleware will run after the postprocess of the next added middleware. After this, the pre/postprocess model seems as powerful as the other models. Implementation-wise, I found pre/postprocess to be quite easy and intuitive. Let me know your thoughts, if you feel we should for go other type of model, I'll implement that. Thanks! |
@nishikantparmariam I'm looking at the middleware you have proposed, and I've run into a few issues that would be solved with an minimum example using your changes. Do you mind posting one? |
@maximlt @philippjfr let me know your comments on #5273 (comment) so we can push this forward. I'm happy to go with either model. @ndmlny-qs you can try this example and notice that we can find out processing time of button click callback. import time
import panel as pn
pn.extension()
class TimingMiddleware(BokehEventMiddleware):
def preprocess(self, syncable, doc, event):
self.start_time = time.time()
def postprocess(self):
process_time = time.time() - self.start_time
print('Took :', process_time)
pn.state.add_bokeh_event_middleware(TimingMiddleware())
btn = pn.widgets.Button(name='Foo')
def callback(event):
# Some computation
time.sleep(2)
btn.on_click(callback)
pn.Row(btn).servable() |
@nishikantparmariam I can see button timings showing up in my terminal. My mouse isn't visible for some reason, but the timings are showing up. Thank you very much for a MRE, it was very helpful. button-timing.webmIf this feature looks good, and it's a feature Panel would like to have, then let me know and I will write documentation and examples for it. |
I've got a playwright test for this feature. Still need to make a few more tests, and documentation around it. |
0b138fa
to
deb0493
Compare
I rebased against the main branch and added playwright tests for the middleware components. The new tests are passing locally and in CI. @philippjfr I can add documentation around using this feature. As @nishikantparmariam mentioned, there are some caveats to how the pre/post processing work that will need to be captured in examples and documentation. |
Solves #5213. See #5213 (comment) also.