flet-charts 1.0.0.dev0__tar.gz → 1.0.0.dev2__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.
Potentially problematic release.
This version of flet-charts might be problematic. Click here for more details.
- {flet_charts-1.0.0.dev0/src/flet_charts.egg-info → flet_charts-1.0.0.dev2}/PKG-INFO +2 -2
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/pyproject.toml +2 -2
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/matplotlib_chart.py +91 -67
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2/src/flet_charts.egg-info}/PKG-INFO +2 -2
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts.egg-info/SOURCES.txt +2 -1
- flet_charts-1.0.0.dev2/src/flet_charts.egg-info/requires.txt +1 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/tests/test_matplotlib_chart_canvas.py +1 -0
- flet_charts-1.0.0.dev2/tests/test_matplotlib_chart_receive_loop.py +122 -0
- flet_charts-1.0.0.dev0/src/flet_charts.egg-info/requires.txt +0 -1
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/LICENSE +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/README.md +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/setup.cfg +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/__init__.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/bar_chart.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/bar_chart_group.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/bar_chart_rod.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/bar_chart_rod_stack_item.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/candlestick_chart.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/candlestick_chart_spot.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/chart_axis.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/line_chart.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/line_chart_data.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/line_chart_data_point.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/matplotlib_backends/backend_flet_agg.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/matplotlib_chart_canvas.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/matplotlib_chart_with_toolbar.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/pie_chart.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/pie_chart_section.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/plotly_chart.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/radar_chart.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/radar_data_set.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/scatter_chart.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/scatter_chart_spot.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/types.py +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts.egg-info/dependency_links.txt +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts.egg-info/top_level.txt +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/flet_charts.dart +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/bar_chart.dart +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/candlestick_chart.dart +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/extension.dart +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/line_chart.dart +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/matplotlib_chart_canvas.dart +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/pie_chart.dart +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/radar_chart.dart +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/scatter_chart.dart +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/utils/bar_chart.dart +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/utils/candlestick_chart.dart +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/utils/charts.dart +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/utils/line_chart.dart +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/utils/pie_chart.dart +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/utils/radar_chart.dart +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/utils/scatter_chart.dart +0 -0
- {flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/pubspec.yaml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flet-charts
|
|
3
|
-
Version: 1.0.0.
|
|
3
|
+
Version: 1.0.0.dev2
|
|
4
4
|
Summary: Interactive chart controls for Flet apps.
|
|
5
5
|
Author-email: Flet contributors <hello@flet.dev>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -11,7 +11,7 @@ Project-URL: Issues, https://github.com/flet-dev/flet/issues
|
|
|
11
11
|
Requires-Python: >=3.10
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
|
-
Requires-Dist: flet==1.0.0.
|
|
14
|
+
Requires-Dist: flet==1.0.0.dev2
|
|
15
15
|
Dynamic: license-file
|
|
16
16
|
|
|
17
17
|
# flet-charts
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "flet-charts"
|
|
3
|
-
version = "1.0.0.
|
|
3
|
+
version = "1.0.0.dev2"
|
|
4
4
|
description = "Interactive chart controls for Flet apps."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [{ name = "Flet contributors", email = "hello@flet.dev" }]
|
|
7
7
|
license = "Apache-2.0"
|
|
8
8
|
requires-python = ">=3.10"
|
|
9
9
|
dependencies = [
|
|
10
|
-
"flet==1.0.0.
|
|
10
|
+
"flet==1.0.0.dev2",
|
|
11
11
|
]
|
|
12
12
|
|
|
13
13
|
[project.urls]
|
|
@@ -433,79 +433,103 @@ class MatplotlibChart(ft.GestureDetector):
|
|
|
433
433
|
"""
|
|
434
434
|
Consume backend messages and apply canvas/state updates.
|
|
435
435
|
|
|
436
|
-
|
|
437
|
-
(
|
|
438
|
-
|
|
436
|
+
Message handling is guarded: applying a frame, and Matplotlib's own
|
|
437
|
+
rendering (which `send_message` runs synchronously, in this task),
|
|
438
|
+
can both raise. Letting that escape would end the loop - nothing
|
|
439
|
+
would drain `_receive_queue` again, so the chart would freeze
|
|
440
|
+
silently and the traceback would only surface later, as an
|
|
441
|
+
unretrieved task exception when the task is garbage-collected.
|
|
439
442
|
"""
|
|
440
443
|
|
|
441
444
|
while True:
|
|
442
445
|
is_binary, content = await self._receive_queue.get()
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
#
|
|
450
|
-
#
|
|
451
|
-
#
|
|
452
|
-
# instead of being eagerly dropped against a stale
|
|
453
|
-
# `_waiting=True` gate. This is the same backpressure shape
|
|
454
|
-
# the 0.85 `_invoke_method` round-trip used to provide.
|
|
455
|
-
if isinstance(content, tuple) and content[0] == "raw":
|
|
456
|
-
logger.debug(f"receive_binary(raw, {len(content[1])})")
|
|
457
|
-
await self.mpl_canvas.apply_raw_packet(content[1])
|
|
458
|
-
elif self.__image_mode == "full":
|
|
459
|
-
logger.debug(f"receive_binary(full, {len(content)})")
|
|
460
|
-
await self.mpl_canvas.apply_full(bytes(content))
|
|
461
|
-
else:
|
|
462
|
-
logger.debug(f"receive_binary(diff, {len(content)})")
|
|
463
|
-
await self.mpl_canvas.apply_diff(bytes(content))
|
|
464
|
-
self.img_count += 1
|
|
446
|
+
try:
|
|
447
|
+
await self._handle_message(is_binary, content)
|
|
448
|
+
except asyncio.CancelledError:
|
|
449
|
+
raise
|
|
450
|
+
except Exception:
|
|
451
|
+
logger.exception("Error handling Matplotlib backend message")
|
|
452
|
+
# A draw that raised never produces the frame that clears
|
|
453
|
+
# this gate, so clear it here or no further draw is ever
|
|
454
|
+
# requested.
|
|
465
455
|
self._waiting = False
|
|
456
|
+
|
|
457
|
+
async def _handle_message(self, is_binary: bool, content: Any) -> None:
|
|
458
|
+
"""
|
|
459
|
+
Apply a single message from the Matplotlib backend.
|
|
460
|
+
|
|
461
|
+
Handles both binary image frames and JSON control messages (cursor
|
|
462
|
+
updates, draw requests, rubber-band overlays, status text, and
|
|
463
|
+
toolbar history state).
|
|
464
|
+
|
|
465
|
+
Args:
|
|
466
|
+
is_binary: Whether `content` is an image frame rather than JSON.
|
|
467
|
+
content: Frame payload or JSON control message.
|
|
468
|
+
"""
|
|
469
|
+
|
|
470
|
+
if is_binary:
|
|
471
|
+
# Hand the frame to the client widget — a raw RGBA frame
|
|
472
|
+
# (pre-encoded 0x04 packet) or full PNG replaces the
|
|
473
|
+
# backbuffer, diff PNG composites onto it. `await`
|
|
474
|
+
# here serialises this receive loop on the Dart-side
|
|
475
|
+
# frame-applied ack: matplotlib "draw" notifications that
|
|
476
|
+
# arrive during the round-trip stay queued in
|
|
477
|
+
# `_receive_queue` and are processed after the ack returns,
|
|
478
|
+
# instead of being eagerly dropped against a stale
|
|
479
|
+
# `_waiting=True` gate. This is the same backpressure shape
|
|
480
|
+
# the 0.85 `_invoke_method` round-trip used to provide.
|
|
481
|
+
if isinstance(content, tuple) and content[0] == "raw":
|
|
482
|
+
logger.debug(f"receive_binary(raw, {len(content[1])})")
|
|
483
|
+
await self.mpl_canvas.apply_raw_packet(content[1])
|
|
484
|
+
elif self.__image_mode == "full":
|
|
485
|
+
logger.debug(f"receive_binary(full, {len(content)})")
|
|
486
|
+
await self.mpl_canvas.apply_full(bytes(content))
|
|
466
487
|
else:
|
|
467
|
-
logger.debug(f"
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
self._rubberband.
|
|
495
|
-
|
|
496
|
-
self.
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
488
|
+
logger.debug(f"receive_binary(diff, {len(content)})")
|
|
489
|
+
await self.mpl_canvas.apply_diff(bytes(content))
|
|
490
|
+
self.img_count += 1
|
|
491
|
+
self._waiting = False
|
|
492
|
+
else:
|
|
493
|
+
logger.debug(f"receive_json({content})")
|
|
494
|
+
if content["type"] == "image_mode":
|
|
495
|
+
self.__image_mode = content["mode"]
|
|
496
|
+
elif content["type"] == "cursor":
|
|
497
|
+
self.mouse_cursor = figure_cursors[content["cursor"]]
|
|
498
|
+
self.update()
|
|
499
|
+
elif content["type"] == "draw" and not self._waiting:
|
|
500
|
+
self._waiting = True
|
|
501
|
+
self.send_message({"type": "draw"})
|
|
502
|
+
elif content["type"] == "rubberband":
|
|
503
|
+
if (
|
|
504
|
+
content["x0"] != -1
|
|
505
|
+
and content["y0"] != -1
|
|
506
|
+
and content["x1"] != -1
|
|
507
|
+
and content["y1"] != -1
|
|
508
|
+
):
|
|
509
|
+
x0 = content["x0"] / self.__dpr
|
|
510
|
+
y0 = self._height - content["y0"] / self.__dpr
|
|
511
|
+
x1 = content["x1"] / self.__dpr
|
|
512
|
+
y1 = self._height - content["y1"] / self.__dpr
|
|
513
|
+
self._rubberband.left = min(x0, x1)
|
|
514
|
+
self._rubberband.top = min(y0, y1)
|
|
515
|
+
self._rubberband.width = abs(x1 - x0)
|
|
516
|
+
self._rubberband.height = abs(y1 - y0)
|
|
517
|
+
self._rubberband.visible = True
|
|
518
|
+
else:
|
|
519
|
+
self._rubberband.visible = False
|
|
520
|
+
self._rubberband.update()
|
|
521
|
+
elif content["type"] == "resize":
|
|
522
|
+
self.send_message({"type": "refresh"})
|
|
523
|
+
elif content["type"] == "message":
|
|
524
|
+
await self._trigger_event("message", {"message": content["message"]})
|
|
525
|
+
elif content["type"] == "history_buttons":
|
|
526
|
+
await self._trigger_event(
|
|
527
|
+
"toolbar_buttons_update",
|
|
528
|
+
{
|
|
529
|
+
"back_enabled": content["Back"],
|
|
530
|
+
"forward_enabled": content["Forward"],
|
|
531
|
+
},
|
|
532
|
+
)
|
|
509
533
|
|
|
510
534
|
def send_message(self, message):
|
|
511
535
|
"""Sends a message to the figure's canvas manager."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: flet-charts
|
|
3
|
-
Version: 1.0.0.
|
|
3
|
+
Version: 1.0.0.dev2
|
|
4
4
|
Summary: Interactive chart controls for Flet apps.
|
|
5
5
|
Author-email: Flet contributors <hello@flet.dev>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -11,7 +11,7 @@ Project-URL: Issues, https://github.com/flet-dev/flet/issues
|
|
|
11
11
|
Requires-Python: >=3.10
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
|
-
Requires-Dist: flet==1.0.0.
|
|
14
|
+
Requires-Dist: flet==1.0.0.dev2
|
|
15
15
|
Dynamic: license-file
|
|
16
16
|
|
|
17
17
|
# flet-charts
|
|
@@ -46,4 +46,5 @@ src/flutter/flet_charts/lib/src/utils/line_chart.dart
|
|
|
46
46
|
src/flutter/flet_charts/lib/src/utils/pie_chart.dart
|
|
47
47
|
src/flutter/flet_charts/lib/src/utils/radar_chart.dart
|
|
48
48
|
src/flutter/flet_charts/lib/src/utils/scatter_chart.dart
|
|
49
|
-
tests/test_matplotlib_chart_canvas.py
|
|
49
|
+
tests/test_matplotlib_chart_canvas.py
|
|
50
|
+
tests/test_matplotlib_chart_receive_loop.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
flet==1.0.0.dev2
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""Fault isolation in ``MatplotlibChart._receive_loop``.
|
|
2
|
+
|
|
3
|
+
The loop is the sole consumer of ``_receive_queue``, and it does more than
|
|
4
|
+
shuffle bytes: ``send_message`` hands a "draw" straight to Matplotlib's
|
|
5
|
+
canvas manager, so the figure renders *inside* this task. Any render error
|
|
6
|
+
— a bad artist, a font that fails to rasterize, a degenerate 3D view —
|
|
7
|
+
therefore surfaces here. Unguarded, it would end the loop: no frame would
|
|
8
|
+
ever be applied again, the chart would freeze with no visible error, and
|
|
9
|
+
the traceback would only appear much later as asyncio's "Task exception was
|
|
10
|
+
never retrieved" when the dead task is garbage-collected.
|
|
11
|
+
|
|
12
|
+
These tests drive the real ``_receive_loop`` with the failures injected at
|
|
13
|
+
the two points that can raise — the canvas apply, and the synchronous
|
|
14
|
+
Matplotlib render behind ``send_message``.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import asyncio
|
|
18
|
+
import types
|
|
19
|
+
|
|
20
|
+
from flet_charts.matplotlib_chart import MatplotlibChart
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _make_chart_standin():
|
|
24
|
+
"""Minimal ``self`` for the real ``_receive_loop``: the queue/state
|
|
25
|
+
attrs ``build()`` would create, plus a fake canvas and ``send_message``
|
|
26
|
+
so a failure can be injected at either point."""
|
|
27
|
+
chart = types.SimpleNamespace()
|
|
28
|
+
chart._receive_queue = asyncio.Queue()
|
|
29
|
+
chart._waiting = False
|
|
30
|
+
chart.img_count = 0
|
|
31
|
+
chart._MatplotlibChart__image_mode = "full"
|
|
32
|
+
chart.applied = []
|
|
33
|
+
chart.sent = []
|
|
34
|
+
|
|
35
|
+
async def apply_raw_packet(packet):
|
|
36
|
+
if packet == b"boom":
|
|
37
|
+
raise RuntimeError("FT_Render_Glyph failed: raster overflow")
|
|
38
|
+
chart.applied.append(packet)
|
|
39
|
+
|
|
40
|
+
chart.mpl_canvas = types.SimpleNamespace(apply_raw_packet=apply_raw_packet)
|
|
41
|
+
|
|
42
|
+
def send_message(message):
|
|
43
|
+
chart.sent.append(message)
|
|
44
|
+
if chart.render_fails:
|
|
45
|
+
raise RuntimeError("FT_Render_Glyph failed: raster overflow")
|
|
46
|
+
|
|
47
|
+
chart.send_message = send_message
|
|
48
|
+
chart.render_fails = False
|
|
49
|
+
chart._handle_message = types.MethodType(MatplotlibChart._handle_message, chart)
|
|
50
|
+
return chart
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _feed_frame(chart, payload=b"frame"):
|
|
54
|
+
chart._receive_queue.put_nowait((True, ("raw", payload)))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
async def _drain(chart):
|
|
58
|
+
"""Run the real loop long enough to consume the queue, then stop it.
|
|
59
|
+
|
|
60
|
+
Returns whether the loop was still alive at that point — a loop killed
|
|
61
|
+
by an exception is `done()` before anything cancels it.
|
|
62
|
+
"""
|
|
63
|
+
task = asyncio.create_task(MatplotlibChart._receive_loop(chart))
|
|
64
|
+
await asyncio.sleep(0.05)
|
|
65
|
+
alive = not task.done()
|
|
66
|
+
task.cancel()
|
|
67
|
+
return alive
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_failing_render_does_not_kill_the_loop():
|
|
71
|
+
"""A "draw" whose render raises must not stop frames that follow."""
|
|
72
|
+
|
|
73
|
+
async def scenario():
|
|
74
|
+
chart = _make_chart_standin()
|
|
75
|
+
chart.render_fails = True
|
|
76
|
+
chart._receive_queue.put_nowait((False, {"type": "draw"}))
|
|
77
|
+
chart.render_fails = False
|
|
78
|
+
_feed_frame(chart)
|
|
79
|
+
alive = await _drain(chart)
|
|
80
|
+
return chart.applied, chart._waiting, alive
|
|
81
|
+
|
|
82
|
+
applied, waiting, alive = asyncio.run(scenario())
|
|
83
|
+
assert applied == [b"frame"], "loop must keep applying frames after a render error"
|
|
84
|
+
assert not waiting, "a draw that raised must not leave the draw gate latched"
|
|
85
|
+
assert alive, "the loop task must still be running"
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_failing_frame_apply_does_not_kill_the_loop():
|
|
89
|
+
"""An error while applying one frame must not lose the next one."""
|
|
90
|
+
|
|
91
|
+
async def scenario():
|
|
92
|
+
chart = _make_chart_standin()
|
|
93
|
+
_feed_frame(chart, b"boom")
|
|
94
|
+
_feed_frame(chart, b"good")
|
|
95
|
+
await _drain(chart)
|
|
96
|
+
return chart.applied
|
|
97
|
+
|
|
98
|
+
assert asyncio.run(scenario()) == [b"good"]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def test_draw_gate_reopens_after_a_render_error():
|
|
102
|
+
"""``_waiting`` gates draw requests; a failed draw never produces the
|
|
103
|
+
frame that clears it, so the loop must clear it itself — otherwise no
|
|
104
|
+
further draw is ever requested and the chart stays frozen."""
|
|
105
|
+
|
|
106
|
+
async def scenario():
|
|
107
|
+
chart = _make_chart_standin()
|
|
108
|
+
chart.render_fails = True
|
|
109
|
+
chart._receive_queue.put_nowait((False, {"type": "draw"}))
|
|
110
|
+
await _drain(chart)
|
|
111
|
+
first = list(chart.sent)
|
|
112
|
+
|
|
113
|
+
chart.render_fails = False
|
|
114
|
+
chart._receive_queue.put_nowait((False, {"type": "draw"}))
|
|
115
|
+
await _drain(chart)
|
|
116
|
+
return first, chart.sent
|
|
117
|
+
|
|
118
|
+
first, sent = asyncio.run(scenario())
|
|
119
|
+
assert first == [{"type": "draw"}]
|
|
120
|
+
assert sent == [{"type": "draw"}, {"type": "draw"}], (
|
|
121
|
+
"a later draw notification must still reach Matplotlib"
|
|
122
|
+
)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
flet==1.0.0.dev0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/bar_chart_rod_stack_item.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/matplotlib_chart_canvas.py
RENAMED
|
File without changes
|
{flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts/matplotlib_chart_with_toolbar.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flet_charts.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
{flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/flet_charts.dart
RENAMED
|
File without changes
|
{flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/bar_chart.dart
RENAMED
|
File without changes
|
|
File without changes
|
{flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/extension.dart
RENAMED
|
File without changes
|
{flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/line_chart.dart
RENAMED
|
File without changes
|
|
File without changes
|
{flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/pie_chart.dart
RENAMED
|
File without changes
|
{flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/radar_chart.dart
RENAMED
|
File without changes
|
{flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/scatter_chart.dart
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flet_charts-1.0.0.dev0 → flet_charts-1.0.0.dev2}/src/flutter/flet_charts/lib/src/utils/charts.dart
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|