diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 44d4156..57d8f9d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -28,11 +28,11 @@ repos: types: [file] types_or: [python, pyi] - repo: https://github.com/psf/black-pre-commit-mirror - rev: 24.4.2 + rev: 24.8.0 hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.5 + rev: v0.6.1 hooks: - id: ruff types: [file] diff --git a/pyproject.toml b/pyproject.toml index 541db5c..9d97fe4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -105,11 +105,13 @@ select = [ "FLY", # flynt "FURB", # refurb "I", # isort + "ICN", # flake8-import-conventions "N", # pep8-naming "PIE", # flake8-pie "PT", # flake8-pytest-style "PYI", # flake8-pyi "Q", # flake8-quotes + "R", # Refactor "RET", # flake8-return "RUF", # Ruff-specific rules "S", # flake8-bandit diff --git a/src/idlemypyextension/client.py b/src/idlemypyextension/client.py index 3d7134c..f9f718b 100644 --- a/src/idlemypyextension/client.py +++ b/src/idlemypyextension/client.py @@ -173,7 +173,7 @@ def _read_request_response_json(request_response: str | bytes) -> Response: async def _request_win32( name: str, request_arguments: str, - timeout: int | None = None, # noqa: TRIO109 + timeout: int | None = None, # noqa: ASYNC109 ) -> Response: """Request from daemon on windows.""" @@ -211,7 +211,7 @@ async def _receive( async def _request_linux( filename: str, request_arguments: str, - timeout: float | None = None, # noqa: TRIO109 + timeout: float | None = None, # noqa: ASYNC109 ) -> Response: def find_frame_in_buffer( buffer: bytearray, @@ -271,7 +271,7 @@ async def request( status_file: str, command: str, *, - timeout: int | None = None, # noqa: TRIO109 + timeout: int | None = None, # noqa: ASYNC109 **kwds: object, ) -> Response: """Send a request to the daemon. @@ -317,7 +317,7 @@ async def stop(status_file: str) -> Response: async def _wait_for_server( status_file: str, - timeout: float = 5.0, # noqa: TRIO109 + timeout: float = 5.0, # noqa: ASYNC109 ) -> bool: """Wait until the server is up. Return False if timed out.""" try: @@ -417,7 +417,7 @@ async def start( async def status( status_file: str, *, - timeout: int = 5, # noqa: TRIO109 + timeout: int = 5, # noqa: ASYNC109 fswatcher_dump_file: str | None = None, ) -> Response: """Ask daemon to return status.""" @@ -433,7 +433,7 @@ async def run( status_file: str, *, flags: list[str], - timeout: int | None = None, # noqa: TRIO109 + timeout: int | None = None, # noqa: ASYNC109 daemon_timeout: int = 0, log_file: str | None = None, export_types: bool = False, @@ -495,7 +495,7 @@ async def check( status_file: str, files: Sequence[str], *, - timeout: int | None = None, # noqa: TRIO109 + timeout: int | None = None, # noqa: ASYNC109 export_types: bool = False, ) -> Response: """Ask the daemon to check a list of files.""" @@ -512,7 +512,7 @@ async def recheck( status_file: str, export_types: bool, *, - timeout: int | None = None, # noqa: TRIO109 + timeout: int | None = None, # noqa: ASYNC109 remove: list[str] | None = None, update: list[str] | None = None, ) -> Response: @@ -551,7 +551,7 @@ async def inspect( location: str, # line:col show: str = "type", # type, attrs, definition *, - timeout: int | None = None, # noqa: TRIO109 + timeout: int | None = None, # noqa: ASYNC109 verbosity: int = 0, limit: int = 0, include_span: bool = False, @@ -582,7 +582,7 @@ async def suggest( function: str, do_json: bool, *, - timeout: int | None = None, # noqa: TRIO109 + timeout: int | None = None, # noqa: ASYNC109 callsites: bool = False, no_errors: bool = False, no_any: bool = False, @@ -609,7 +609,7 @@ async def suggest( async def hang( status_file: str, *, - timeout: int = 1, # noqa: TRIO109 + timeout: int = 1, # noqa: ASYNC109 ) -> Response: """Hang for 100 seconds, as a debug hack.""" if not isinstance(timeout, int): diff --git a/src/idlemypyextension/extension.py b/src/idlemypyextension/extension.py index 4a0b58e..05bb193 100644 --- a/src/idlemypyextension/extension.py +++ b/src/idlemypyextension/extension.py @@ -5,7 +5,7 @@ from __future__ import annotations # IDLE Mypy daemon integration extension -# Copyright (C) 2023 CoolCat467 +# Copyright (C) 2023-2024 CoolCat467 # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -34,7 +34,7 @@ from idlelib.config import idleConf from typing import TYPE_CHECKING, Any, ClassVar, Final -from idlemypyextension import annotate, client, tktrio, utils +from idlemypyextension import annotate, client, mttkinter, tktrio, utils if TYPE_CHECKING: from collections.abc import Callable @@ -759,6 +759,8 @@ def unregister_async_events(self) -> None: def close(self) -> None: """Extension cleanup before IDLE window closes.""" # Wrapped in try except so failure doesn't cause zombie windows. + del self.triorun + mttkinter.restore() try: self.unregister_async_events() except Exception as exc: diff --git a/src/idlemypyextension/mttkinter.py b/src/idlemypyextension/mttkinter.py index 0a9d91d..ba0ab94 100644 --- a/src/idlemypyextension/mttkinter.py +++ b/src/idlemypyextension/mttkinter.py @@ -277,11 +277,24 @@ def _check_events(tk: Tk) -> None: tk.after(tk_obj._check_period, _check_events, tk) +def restore() -> None: + """Restore original functions.""" + if hasattr(Tk, "__original__init__mtTkinter"): + Tk.__init__ = Tk.__original__init__mtTkinter + del Tk.__original__init__mtTkinter + + if hasattr(Tk, "__original__destroy"): + Tk.destroy = Tk.__original__destroy + del Tk.__original__destroy + + """Perform in-memory modification of Tkinter module""" # Replace Tk's original __init__ with the hook. -Tk.__original__init__mtTkinter = Tk.__init__ # type: ignore[attr-defined] -Tk.__init__ = _tk__init__ # type: ignore[ method-assign] +if not hasattr(Tk, "__original__init__mtTkinter"): + Tk.__original__init__mtTkinter = Tk.__init__ # type: ignore[attr-defined] + Tk.__init__ = _tk__init__ # type: ignore[ method-assign] # Replace Tk's original destroy with the hook. -Tk.__original__destroy = Tk.destroy # type: ignore[attr-defined] -Tk.destroy = _tk_destroy # type: ignore[ method-assign] +if not hasattr(Tk, "__original__destroy"): + Tk.__original__destroy = Tk.destroy # type: ignore[attr-defined] + Tk.destroy = _tk_destroy # type: ignore[ method-assign] diff --git a/src/idlemypyextension/tktrio.py b/src/idlemypyextension/tktrio.py index 68bb1c5..bc35b70 100644 --- a/src/idlemypyextension/tktrio.py +++ b/src/idlemypyextension/tktrio.py @@ -166,10 +166,9 @@ def __new__( if not is_tk_wm_and_misc_subclass(root): raise ValueError("Must be subclass of both tk.Misc and tk.Wm") ref = getattr(root, "__trio__", None) + if ref is not None: - obj = ref() - if isinstance(obj, cls): - return obj + return ref() return super().__new__(cls) def __init__( diff --git a/tests/test_annotate.py b/tests/test_annotate.py index c7c1584..8ccca35 100644 --- a/tests/test_annotate.py +++ b/tests/test_annotate.py @@ -8,6 +8,7 @@ from typing import TYPE_CHECKING import pytest + from idlemypyextension import annotate if TYPE_CHECKING: diff --git a/tests/test_utils.py b/tests/test_utils.py index fddd7a6..1d6872d 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,6 +1,7 @@ from __future__ import annotations import pytest + from idlemypyextension import utils