From fa36460f994c4148f8c4731fc8c27d38a2a2897c Mon Sep 17 00:00:00 2001 From: Ankith Date: Sun, 5 Jan 2025 19:19:58 +0530 Subject: [PATCH] event.peek return bool, minor doc/stub fixes Co-authored-by: zoldalma <46655437+zoldalma999@users.noreply.github.com> Co-authored-by: Dan Lawrence --- buildconfig/stubs/pygame/event.pyi | 12 ++++++----- docs/reST/ref/event.rst | 7 +++++- src_c/event.c | 8 +++---- test/event_test.py | 34 ++++++++++++++++++++++-------- 4 files changed, 42 insertions(+), 19 deletions(-) diff --git a/buildconfig/stubs/pygame/event.pyi b/buildconfig/stubs/pygame/event.pyi index 7f8ed1a6b7..1ad71ac57a 100644 --- a/buildconfig/stubs/pygame/event.pyi +++ b/buildconfig/stubs/pygame/event.pyi @@ -4,7 +4,8 @@ from pygame.typing import SequenceLike @final class Event: - type: int + @property + def type(self) -> int: ... __dict__: dict[str, Any] __hash__: None # type: ignore def __init__( @@ -17,20 +18,21 @@ class Event: # this is at the bottom because mypy complains if this declaration comes # before any uses of the dict[] typehinting because of the same naming - dict: dict[str, Any] + @property + def dict(self) -> dict[str, Any]: ... _EventTypes = Union[int, SequenceLike[int]] def pump() -> None: ... def get( eventtype: Optional[_EventTypes] = None, - pump: Any = True, + pump: bool = True, exclude: Optional[_EventTypes] = None, ) -> list[Event]: ... def poll() -> Event: ... def wait(timeout: int = 0) -> Event: ... -def peek(eventtype: Optional[_EventTypes] = None, pump: Any = True) -> bool: ... -def clear(eventtype: Optional[_EventTypes] = None, pump: Any = True) -> None: ... +def peek(eventtype: Optional[_EventTypes] = None, pump: bool = True) -> bool: ... +def clear(eventtype: Optional[_EventTypes] = None, pump: bool = True) -> None: ... def event_name(type: int, /) -> str: ... def set_blocked(type: Optional[_EventTypes], /) -> None: ... def set_allowed(type: Optional[_EventTypes], /) -> None: ... diff --git a/docs/reST/ref/event.rst b/docs/reST/ref/event.rst index 186fa37717..319f256c3e 100644 --- a/docs/reST/ref/event.rst +++ b/docs/reST/ref/event.rst @@ -324,10 +324,15 @@ On Android, the following events can be generated queue. If a sequence of event types is passed, this will return ``True`` if any of those events are on the queue. + When ``eventtype`` is not passed or ``None``, this function will return ``True`` if + there's any event on the queue, and return ``False`` if the queue is empty. + If ``pump`` is ``True`` (the default), then :func:`pygame.event.pump()` will be called. .. versionchangedold:: 1.9.5 Added ``pump`` argument + .. versionchanged:: 2.5.3 no longer mistakenly returns an event when ``eventtype`` is None or not passed. + .. ## pygame.event.peek ## .. function:: clear @@ -491,7 +496,7 @@ On Android, the following events can be generated Read-only. The event type identifier. For user created event objects, this is the ``type`` argument passed to - :func:`pygame.event.Event()`. + :class:`pygame.event.Event()`. For example, some predefined event identifiers are ``QUIT`` and ``MOUSEMOTION``. diff --git a/src_c/event.c b/src_c/event.c index c7838a0ee8..5d87e5a6d4 100644 --- a/src_c/event.c +++ b/src_c/event.c @@ -1591,9 +1591,9 @@ static PyTypeObject pgEvent_Type; #define OFF(x) offsetof(pgEventObject, x) static PyMemberDef pg_event_members[] = { - {"__dict__", T_OBJECT, OFF(dict), READONLY}, - {"type", T_INT, OFF(type), READONLY}, - {"dict", T_OBJECT, OFF(dict), READONLY}, + {"__dict__", T_OBJECT, OFF(dict), READONLY, DOC_EVENT_EVENT_DICT}, + {"type", T_INT, OFF(type), READONLY, DOC_EVENT_EVENT_TYPE}, + {"dict", T_OBJECT, OFF(dict), READONLY, DOC_EVENT_EVENT_DICT}, {NULL} /* Sentinel */ }; @@ -2262,7 +2262,7 @@ pg_event_peek(PyObject *self, PyObject *args, PyObject *kwargs) res = PG_PEEP_EVENT_ALL(&event, 1, SDL_PEEKEVENT); if (res < 0) return RAISE(pgExc_SDLError, SDL_GetError()); - return pgEvent_New(res ? &event : NULL); + return PyBool_FromLong(res); } else { seq = _pg_eventtype_as_seq(obj, &len); diff --git a/test/event_test.py b/test/event_test.py index 43e4783eee..f4ce259232 100644 --- a/test/event_test.py +++ b/test/event_test.py @@ -249,16 +249,32 @@ def test_clear(self): self.assertRaises(ValueError, pygame.event.clear, 0x0010FFFFF) self.assertRaises(TypeError, pygame.event.get, ["a", "b", "c"]) + def test_peek_no_arg(self): + pygame.event.clear() + # do a strict "is" check and not just a simple truthy-test to check that + # we have a boolean instance. + self.assertIs(pygame.event.peek(), False) + self.assertIs(pygame.event.peek(None), False) + + # peek should return True if there's any event on the queue + pygame.event.post(pygame.event.Event(pygame.USEREVENT)) + self.assertIs(pygame.event.peek(), True) + self.assertIs(pygame.event.peek(None), True) + def test_peek(self): - pygame.event.peek() - pygame.event.peek(None) - pygame.event.peek(None, True) - - pygame.event.peek(pump=False) - pygame.event.peek(pump=True) - pygame.event.peek(eventtype=None) - pygame.event.peek(eventtype=[pygame.KEYUP, pygame.KEYDOWN]) - pygame.event.peek(eventtype=pygame.USEREVENT, pump=False) + self.assertIsInstance(pygame.event.peek(), bool) + self.assertIsInstance(pygame.event.peek(None), bool) + self.assertIsInstance(pygame.event.peek(None, True), bool) + + self.assertIsInstance(pygame.event.peek(pump=False), bool) + self.assertIsInstance(pygame.event.peek(pump=True), bool) + self.assertIsInstance(pygame.event.peek(eventtype=None), bool) + self.assertIsInstance( + pygame.event.peek(eventtype=[pygame.KEYUP, pygame.KEYDOWN]), bool + ) + self.assertIsInstance( + pygame.event.peek(eventtype=pygame.USEREVENT, pump=False), bool + ) class Foo: pass