Skip to content

Commit

Permalink
Merge pull request #1457 from Textualize/win-sleep
Browse files Browse the repository at this point in the history
Win sleep
  • Loading branch information
willmcgugan committed Dec 30, 2022
2 parents c261894 + 91e23ff commit 4cf3aef
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 12 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/).

## [0.9.1] - 2022-12-30

### Added

- Added textual._win_sleep for Python on Windows < 3.11 https://github.com/Textualize/textual/pull/1457

## [0.9.0] - 2022-12-30

### Added
Expand Down Expand Up @@ -316,6 +322,7 @@ https://textual.textualize.io/blog/2022/11/08/version-040/#version-040
- New handler system for messages that doesn't require inheritance
- Improved traceback handling

[0.9.1]: https://github.com/Textualize/textual/compare/v0.9.0...v0.9.1
[0.9.0]: https://github.com/Textualize/textual/compare/v0.8.2...v0.9.0
[0.8.2]: https://github.com/Textualize/textual/compare/v0.8.1...v0.8.2
[0.8.1]: https://github.com/Textualize/textual/compare/v0.8.0...v0.8.1
Expand Down
3 changes: 1 addition & 2 deletions docs/blog/posts/better-sleep-on-windows.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ async def sleep(sleep_for: float) -> None:
Args:
sleep_for (float): Seconds to sleep for.
"""
print("sleep")
"""
await get_running_loop().run_in_executor(None, time_sleep, sleep_for)

```
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "textual"
version = "0.9.0"
version = "0.9.1"
homepage = "https://github.com/Textualize/textual"
description = "Modern Text User Interface framework"
authors = ["Will McGugan <[email protected]>"]
Expand Down
23 changes: 16 additions & 7 deletions src/textual/_time.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import platform
import sys

from asyncio import sleep as asyncio_sleep, get_running_loop
from time import monotonic, perf_counter, sleep as time_sleep
Expand All @@ -16,15 +17,23 @@

if WINDOWS:

async def sleep(sleep_for: float) -> None:
"""An asyncio sleep.
if sys.version_info >= (3, 11, 0):

On Windows this achieves a better granularity that asyncio.sleep
async def sleep(sleep_for: float) -> None:
"""An asyncio sleep.
Args:
sleep_for (float): Seconds to sleep for.
"""
await get_running_loop().run_in_executor(None, time_sleep, sleep_for)
On Windows this achieves a better granularity that asyncio.sleep
Args:
sleep_for (float): Seconds to sleep for.
"""
await get_running_loop().run_in_executor(None, time_sleep, sleep_for)

else:
from ._win_sleep import sleep as win_sleep

async def sleep(sleep_for: float) -> None:
await get_running_loop().run_in_executor(None, win_sleep, sleep_for)

else:
sleep = asyncio_sleep
48 changes: 48 additions & 0 deletions src/textual/_win_sleep.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import ctypes
from ctypes.wintypes import LARGE_INTEGER
from time import sleep as time_sleep

__all__ = ["sleep"]

kernel32 = ctypes.windll.kernel32

INFINITE = 0xFFFFFFFF
WAIT_FAILED = 0xFFFFFFFF
CREATE_WAITABLE_TIMER_HIGH_RESOLUTION = 0x00000002


def sleep(sleep_for: float) -> None:
"""A replacement sleep for Windows.
Python 3.11 added a more accurate sleep. This may be used on < Python 3.11
Args:
sleep_for (float): Seconds to sleep for.
"""
handle = kernel32.CreateWaitableTimerExW(
None,
None,
CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
0x1F0003,
)
if not handle:
time_sleep(sleep_for)
return

sleep_for -= 1 / 1000
if not kernel32.SetWaitableTimer(
handle,
ctypes.byref(LARGE_INTEGER(int(sleep_for * -10_000_000))),
0,
None,
None,
0,
):
kernel32.CloseHandle(handle)
print("error")
time_sleep(sleep_for)
return

if kernel32.WaitForSingleObject(handle, INFINITE) == WAIT_FAILED:
time_sleep(sleep_for)
kernel32.CloseHandle(handle)
5 changes: 3 additions & 2 deletions tests/snapshot_tests/test_snapshots.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ def test_input_and_focus(snap_compare):
"tab",
*"Darren", # Focus first input, write "Darren"
"tab",
*"Burns", # Tab focus to second input, write "Burns"
*"Burns",
"_", # Tab focus to second input, write "Burns"
]
assert snap_compare(WIDGET_EXAMPLES_DIR / "input.py", press=press)

Expand Down Expand Up @@ -178,6 +179,6 @@ def test_demo(snap_compare):
"""Test the demo app (python -m textual)"""
assert snap_compare(
Path("../../src/textual/demo.py"),
press=["down", "down", "down", "_"],
press=["down", "down", "down", "_", "_"],
terminal_size=(100, 30),
)

0 comments on commit 4cf3aef

Please sign in to comment.