-
Notifications
You must be signed in to change notification settings - Fork 864
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
Rendering related RecursionError: maximum recursion depth exceeded while calling a Python object
#5669
Comments
Here's the stacktrace:
|
I've tried mashing the mouse button until my hand was sore, but I couldn't seem to reproduce this with your example? |
Yes, unfortunately I also couldn't reproduce with this example, but I wanted to provide some context for when the crash happens. The real scenario is very similar, except there is some data gathered from the network on the dialog, and the underlying screen also keeps updating the header.
I think the application load plays a role here. And it's required to click to close the dialog when an |
Okay, finally I've got the reproduction, however I had to MRE: from __future__ import annotations
from datetime import datetime
import aiohttp
from textual import on, work
from textual.app import App, ComposeResult
from textual.containers import Horizontal, Vertical, VerticalScroll
from textual.events import Click, Mount
from textual.screen import ModalScreen
from textual.widgets import Button, Placeholder, Static
class Dialog(ModalScreen):
DEFAULT_CSS = """
Dialog {
align: center middle;
background: $background 85%;
#dialog-content {
border-title-style: bold;
border-title-color: $text;
border-title-background: $primary;
border: $primary outer;
background: $panel 80%;
padding: 1;
width: 50%;
height: auto;
}
}
"""
def __init__(self, item: str) -> None:
super().__init__()
self._item = item
self._is_closing = False
def compose(self) -> ComposeResult:
with Vertical(id="dialog-content"):
yield Static("This is a dialog")
yield Static(f"You clicked on {self._item}")
data = Static("", id="data")
data.loading = True
yield data
yield Button("Close", name="close", id="close-dialog")
@property
def data_widget(self) -> Static:
return self.query_exactly_one("#data", Static)
@on(Mount)
def schedule_data_updating(self) -> None:
self.set_interval(1, self._update)
@on(Button.Pressed, "#close-dialog")
def close_by_button(self) -> None:
self.close_dialog()
@on(Click)
def close_by_clicking_outside(self, event: Click) -> None:
"""Close the Dialog if the user clicks outside the modal content."""
if self.get_widget_at(event.screen_x, event.screen_y)[0] is self:
self.close_dialog()
def close_dialog(self) -> None:
async def impl() -> None:
await self.dismiss()
self._is_closing = False
if self._is_closing:
return
self._is_closing = True
self.app.run_worker(impl())
@work(name="update data worker")
async def _update(self) -> None:
data_widget = self.data_widget
data_widget.loading = False
async with aiohttp.ClientSession() as session, session.get("https://jsonplaceholder.typicode.com/posts/1") as response:
data = await response.json()
data_widget.update(f"Data loaded: {datetime.now()}- {data}")
class ExampleApp(App):
DEFAULT_CSS = """
Button {
border: none !important;
&:hover {
border: none !important;
}
}
Placeholder {
height: 3;
}
.item {
height: auto;
.item-name {
width: auto;
}
}
"""
def compose(self) -> ComposeResult:
for i in range(10):
yield Placeholder(variant="text")
with VerticalScroll():
for i in range(30):
with Horizontal(classes="item"):
item_name = f"item {i}"
yield Static(item_name, classes="item-name")
yield Button("Show dialog", name=item_name, id="push-dialog")
@on(Mount)
def schedule_data_updating(self) -> None:
self.set_interval(1, self._update)
@on(Button.Pressed, "#push-dialog")
async def push_dialog(self, event: Button.Pressed) -> None:
await self.push_screen(Dialog(event.button.name))
async def _update(self) -> None:
for placeholder in self.screen.query(Placeholder):
await placeholder.recompose()
if __name__ == "__main__":
ExampleApp().run() Also there's more info in the output: out
|
Worth mentioning: this happens on the revision d9f7ffd, because it includes a fix for other crashes (#5641)
Sorry, but I do not yet have an MRE that can reproduce the problem. This happens when pushing/dismissing a screen quickly enough. I've included some code that presents a similar situation.
Maybe related: #5629
In a real scenario spamming LMB on "Show dialog" causes the dialog to be showed and closed again and again. After a while, it crashes with RecursionError.
The text was updated successfully, but these errors were encountered: