better-rtplot 0.4.8__tar.gz → 0.4.9__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 (36) hide show
  1. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/PKG-INFO +1 -1
  2. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/pyproject.toml +1 -1
  3. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/client.py +74 -6
  4. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/server_browser.py +6 -0
  5. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/LICENSE +0 -0
  6. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/README.md +0 -0
  7. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/interactive_test.py +0 -0
  8. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/saved_plots/.gitignore +0 -0
  9. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/server.py +0 -0
  10. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/server_browser_gui.py +0 -0
  11. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/index.html +0 -0
  12. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/auto-render.min.js +0 -0
  13. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  14. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  15. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  16. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  17. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  18. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
  19. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  20. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
  21. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
  22. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  23. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
  24. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  25. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  26. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  27. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
  28. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  29. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  30. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  31. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  32. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  33. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/katex.min.css +0 -0
  34. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/katex/katex.min.js +0 -0
  35. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/uPlot.iife.min.js +0 -0
  36. {better_rtplot-0.4.8 → better_rtplot-0.4.9}/rtplot/static/uPlot.min.css +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: better-rtplot
3
- Version: 0.4.8
3
+ Version: 0.4.9
4
4
  Summary:
5
5
  License: GPL V3.0
6
6
  Author: jmontp
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "better-rtplot"
3
- version = "0.4.8"
3
+ version = "0.4.9"
4
4
  description = ""
5
5
  authors = ["jmontp <jmontp@umich.edu>"]
6
6
  license = "GPL V3.0"
@@ -414,8 +414,17 @@ def send_array(A, flags=0, copy=True, track=False):
414
414
  socket.send(A, flags, copy=copy, track=track)
415
415
 
416
416
 
417
- def initialize_plots(plot_descriptions=1):
418
- """Send a json description of desired plot.
417
+ def initialize_plots(plot_descriptions=1, handshake_timeout=2.0):
418
+ """Send a json description of desired plot and block until the
419
+ server acknowledges it.
420
+
421
+ Without the handshake, a fast script that calls ``initialize_plots()``
422
+ and immediately starts firing ``send_array()`` can lose the config
423
+ frame to ZMQ's PUB/SUB slow-joiner window — the server then drops
424
+ every subsequent data frame because no plot is declared yet and the
425
+ browser just stays blank. We resend the config on a short schedule
426
+ until the server PUSHes back a ``config_ack``, guaranteeing the
427
+ plot is live by the time this call returns.
419
428
 
420
429
  Inputs
421
430
  ------
@@ -426,6 +435,11 @@ def initialize_plots(plot_descriptions=1):
426
435
  - list of str: one plot, one trace per name
427
436
  - list of list of str: one plot per sublist
428
437
  - list of dict: multiple plots, each with full styling
438
+ handshake_timeout:
439
+ Max seconds to wait for the config_ack. On timeout we print a
440
+ warning and return (so an old server without the handshake
441
+ feature, or a server on a flaky network, doesn't block the
442
+ caller forever). Set to 0 to skip the handshake entirely.
429
443
  """
430
444
  global plot_desc_dict
431
445
 
@@ -477,11 +491,65 @@ def initialize_plots(plot_descriptions=1):
477
491
  else:
478
492
  raise TypeError("Incorrect usage of initialize_plots, verify github for usage")
479
493
 
480
- #Send the category
481
- socket.send_string(SENDING_PLOT_UPDATE)
494
+ _send_initialize_with_handshake(plot_desc_dict, handshake_timeout)
482
495
 
483
- #Send the description
484
- socket.send_json(plot_desc_dict)
496
+
497
+ def _send_initialize_with_handshake(cfg, timeout):
498
+ """Publish ``cfg`` and block until the server acks it.
499
+
500
+ Any control events (button presses, slider updates) that happen to
501
+ arrive during the handshake are stashed in the module-level caches
502
+ so the next ``poll_controls()`` call still sees them — we don't
503
+ want the handshake to swallow real user interaction.
504
+ """
505
+ global _control_button_events
506
+
507
+ def _send_once():
508
+ socket.send_string(SENDING_PLOT_UPDATE)
509
+ socket.send_json(cfg)
510
+
511
+ _send_once()
512
+
513
+ if timeout is None or timeout <= 0:
514
+ return # opt-out: fire-and-forget like the pre-handshake behavior
515
+
516
+ deadline = time.time() + timeout
517
+ resend_interval = 0.2
518
+ last_send = time.time()
519
+
520
+ poller = zmq.Poller()
521
+ poller.register(control_socket, zmq.POLLIN)
522
+
523
+ while time.time() < deadline:
524
+ remaining_ms = max(10, int((deadline - time.time()) * 1000))
525
+ next_resend_ms = max(1, int((last_send + resend_interval - time.time()) * 1000))
526
+ wait_ms = min(remaining_ms, next_resend_ms)
527
+ events = dict(poller.poll(wait_ms))
528
+ if control_socket in events:
529
+ try:
530
+ event = control_socket.recv_json(flags=zmq.NOBLOCK)
531
+ except (zmq.Again, zmq.ZMQError):
532
+ continue
533
+ evtype = event.get("type")
534
+ if evtype == "config_ack":
535
+ return
536
+ elif evtype == "button":
537
+ _control_button_events.append(event.get("id"))
538
+ elif evtype == "slider":
539
+ _control_slider_values[event.get("id")] = float(event.get("value", 0.0))
540
+ # Unknown / resend_config: ignore during handshake.
541
+ # Resend if the window elapsed without an ack; PUB/SUB will
542
+ # drop the first send during slow-join but retries land.
543
+ if time.time() - last_send >= resend_interval:
544
+ _send_once()
545
+ last_send = time.time()
546
+
547
+ print(
548
+ "rtplot.client: initialize_plots() timed out waiting for server ack"
549
+ f" after {timeout:.1f}s — the plot config may have been dropped."
550
+ " If you're on an older server (rtplot < 0.4.9) this warning is"
551
+ " expected and harmless."
552
+ )
485
553
 
486
554
 
487
555
  def set_display(display_id: str, value):
@@ -780,6 +780,12 @@ async def zmq_receiver(tab: Tab):
780
780
  last_time = now
781
781
  tab.status = "streaming"
782
782
  tab.error = None
783
+ # Blocking-handshake ack: tells initialize_plots() on the
784
+ # client side that the config made it past PUB/SUB's
785
+ # slow-joiner window so it can stop resending and return.
786
+ # Old clients ignore unknown event types, so this is safe
787
+ # to emit unconditionally.
788
+ await send_control_event(tab, {"type": "config_ack"})
783
789
  await broadcast_text_tab(tab.id, tab.config_message)
784
790
  await broadcast_tab(tab.id)
785
791
  snap = make_snapshot_message(tab)
File without changes
File without changes