From 8400a68b7cdccb0145585e9c1c8a2cb7665f034a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Gir=C3=A3o=20Serr=C3=A3o?= <5621605+rodrigogiraoserrao@users.noreply.github.com> Date: Thu, 8 Feb 2024 11:54:01 +0000 Subject: [PATCH] Add Widget.lock, remove Tree.lock. --- CHANGELOG.md | 6 ++++++ src/textual/widget.py | 10 +++++++++- src/textual/widgets/_tree.py | 3 --- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 391eefa3a0..7410e73bd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## Unreleased + +### Added + +- Added an `asyncio` lock attribute `Widget.lock` to be used to synchronize widget state https://github.com/Textualize/textual/issues/4134 + ## [0.49.1] - 2023-02-08 ### Fixed diff --git a/src/textual/widget.py b/src/textual/widget.py index 85daa5025e..d2167c45f1 100644 --- a/src/textual/widget.py +++ b/src/textual/widget.py @@ -4,7 +4,7 @@ from __future__ import annotations -from asyncio import create_task, wait +from asyncio import Lock, create_task, wait from collections import Counter from fractions import Fraction from itertools import islice @@ -372,6 +372,14 @@ def __init__( if self.BORDER_SUBTITLE: self.border_subtitle = self.BORDER_SUBTITLE + self.lock = Lock() + """`asyncio` lock to be used to synchronize the state of the widget. + + Two different tasks might call methods on a widget at the same time, which + might result in a race condition. + This can be fixed by adding `async with widget.lock:` around the method calls. + """ + virtual_size: Reactive[Size] = Reactive(Size(0, 0), layout=True) """The virtual (scrollable) [size][textual.geometry.Size] of the widget.""" diff --git a/src/textual/widgets/_tree.py b/src/textual/widgets/_tree.py index 3e0a2d8cb4..f218ae86f2 100644 --- a/src/textual/widgets/_tree.py +++ b/src/textual/widgets/_tree.py @@ -2,7 +2,6 @@ from __future__ import annotations -from asyncio import Lock from dataclasses import dataclass from typing import TYPE_CHECKING, ClassVar, Generic, Iterable, NewType, TypeVar, cast @@ -618,8 +617,6 @@ def __init__( self._line_cache: LRUCache[LineCacheKey, Strip] = LRUCache(1024) self._tree_lines_cached: list[_TreeLine[TreeDataType]] | None = None self._cursor_node: TreeNode[TreeDataType] | None = None - self.lock = Lock() - """Used to synchronise stateful directory tree operations.""" super().__init__(name=name, id=id, classes=classes, disabled=disabled)