From 15a6124d2d88001512d98af98d415205bc8633b6 Mon Sep 17 00:00:00 2001 From: Xiddoc Date: Sat, 15 Feb 2025 13:30:07 +0200 Subject: [PATCH 1/9] Add types for pyperclip API --- stubs/pyperclip/METADATA.toml | 2 ++ stubs/pyperclip/pyperclip/__init__.pyi | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 stubs/pyperclip/METADATA.toml create mode 100644 stubs/pyperclip/pyperclip/__init__.pyi diff --git a/stubs/pyperclip/METADATA.toml b/stubs/pyperclip/METADATA.toml new file mode 100644 index 000000000000..1a3e83373161 --- /dev/null +++ b/stubs/pyperclip/METADATA.toml @@ -0,0 +1,2 @@ +version = "1.9.*" +upstream_repository = "https://github.com/asweigart/pyperclip" diff --git a/stubs/pyperclip/pyperclip/__init__.pyi b/stubs/pyperclip/pyperclip/__init__.pyi new file mode 100644 index 000000000000..62ec9644b49e --- /dev/null +++ b/stubs/pyperclip/pyperclip/__init__.pyi @@ -0,0 +1,26 @@ +__all__ = ["copy", "paste", "set_clipboard", "determine_clipboard"] + +from collections.abc import Callable +from typing import Any, Literal, TypeAlias + +class PyperclipException(RuntimeError): ... + +class PyperclipWindowsException(PyperclipException): + def __init__(self, message: str) -> None: ... + +class PyperclipTimeoutException(PyperclipException): ... + +# Wrapper for ctypes calls, should not be exposed to the developer +class CheckedCall: + def __init__(self, f: Callable[[...], Any]) -> None: ... + def __call__(self, *args: Any): ... + def __setattr__(self, key: str, value: Any) -> None: ... + +ClipboardMechanismName: TypeAlias = Literal["pbcopy", "pyobjc", "qt", "xclip", "xsel", "wl-clipboard", "klipper", "windows", "no"] +ClipboardCopyMechanism: TypeAlias = Callable[[str], None] +ClipboardPasteMechanism: TypeAlias = Callable[[], str] + +def copy(text: str) -> None: ... +def paste() -> str: ... +def set_clipboard(clipboard: ClipboardMechanismName) -> None: ... +def determine_clipboard() -> tuple[ClipboardCopyMechanism, ClipboardPasteMechanism]: ... From aad2a865c7e125478b0c277facc9494a1fc5b06a Mon Sep 17 00:00:00 2001 From: Xiddoc Date: Sat, 15 Feb 2025 13:42:12 +0200 Subject: [PATCH 2/9] Explicitly type clipboard package as well (literal re-package of pyperclip) --- stubs/clipboard/METADATA.toml | 2 ++ stubs/clipboard/clipboard.pyi | 1 + 2 files changed, 3 insertions(+) create mode 100644 stubs/clipboard/METADATA.toml create mode 100644 stubs/clipboard/clipboard.pyi diff --git a/stubs/clipboard/METADATA.toml b/stubs/clipboard/METADATA.toml new file mode 100644 index 000000000000..9b24a670e19b --- /dev/null +++ b/stubs/clipboard/METADATA.toml @@ -0,0 +1,2 @@ +version = "0.0.*" +upstream_repository = "https://github.com/terryyin/clipboard" diff --git a/stubs/clipboard/clipboard.pyi b/stubs/clipboard/clipboard.pyi new file mode 100644 index 000000000000..86e0b96acaca --- /dev/null +++ b/stubs/clipboard/clipboard.pyi @@ -0,0 +1 @@ +from pyperclip import copy as copy, paste as paste From 125339ce7b993146aa1da35f17cfae7e8b0ec7c2 Mon Sep 17 00:00:00 2001 From: Xiddoc Date: Sat, 15 Feb 2025 14:09:44 +0200 Subject: [PATCH 3/9] Add Protocol to represent DLL-imported low level functions for pyperclip --- stubs/pyperclip/pyperclip/__init__.pyi | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/stubs/pyperclip/pyperclip/__init__.pyi b/stubs/pyperclip/pyperclip/__init__.pyi index 62ec9644b49e..2213d6a969cb 100644 --- a/stubs/pyperclip/pyperclip/__init__.pyi +++ b/stubs/pyperclip/pyperclip/__init__.pyi @@ -1,7 +1,8 @@ __all__ = ["copy", "paste", "set_clipboard", "determine_clipboard"] from collections.abc import Callable -from typing import Any, Literal, TypeAlias +from typing import Any, Literal, TypeAlias, Protocol + class PyperclipException(RuntimeError): ... @@ -10,9 +11,14 @@ class PyperclipWindowsException(PyperclipException): class PyperclipTimeoutException(PyperclipException): ... + +class WinDLLUser32Function(Protocol): + def __call__(self, *args: Any) -> Any: ... + + # Wrapper for ctypes calls, should not be exposed to the developer class CheckedCall: - def __init__(self, f: Callable[[...], Any]) -> None: ... + def __init__(self, f: WinDLLUser32Function) -> None: ... def __call__(self, *args: Any): ... def __setattr__(self, key: str, value: Any) -> None: ... From f62c8876865e68dfa62b500d2cc18774a6c456cd Mon Sep 17 00:00:00 2001 From: Xiddoc Date: Sat, 15 Feb 2025 14:11:02 +0200 Subject: [PATCH 4/9] Add dependency: clipboard package relies on pyperclip --- stubs/clipboard/METADATA.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/stubs/clipboard/METADATA.toml b/stubs/clipboard/METADATA.toml index 9b24a670e19b..7d8a8ed6aed2 100644 --- a/stubs/clipboard/METADATA.toml +++ b/stubs/clipboard/METADATA.toml @@ -1,2 +1,3 @@ version = "0.0.*" upstream_repository = "https://github.com/terryyin/clipboard" +requires = ["pyperclip"] From 6e1db2f7758b4aee1b9c34249c235c649dd04bdc Mon Sep 17 00:00:00 2001 From: Xiddoc Date: Sat, 15 Feb 2025 14:38:30 +0200 Subject: [PATCH 5/9] Both pyperclip and clipboard support all OSes --- stubs/clipboard/METADATA.toml | 4 ++++ stubs/pyperclip/METADATA.toml | 4 ++++ stubs/pyperclip/pyperclip/__init__.pyi | 21 ++++++++++----------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/stubs/clipboard/METADATA.toml b/stubs/clipboard/METADATA.toml index 7d8a8ed6aed2..1091178a5a77 100644 --- a/stubs/clipboard/METADATA.toml +++ b/stubs/clipboard/METADATA.toml @@ -1,3 +1,7 @@ version = "0.0.*" upstream_repository = "https://github.com/terryyin/clipboard" requires = ["pyperclip"] + +[tool.stubtest] +platforms = ["win32", "linux", "darwin"] +stubtest_requirements = ["pyperclip"] diff --git a/stubs/pyperclip/METADATA.toml b/stubs/pyperclip/METADATA.toml index 1a3e83373161..d8fd275f4016 100644 --- a/stubs/pyperclip/METADATA.toml +++ b/stubs/pyperclip/METADATA.toml @@ -1,2 +1,6 @@ version = "1.9.*" upstream_repository = "https://github.com/asweigart/pyperclip" + +[tool.stubtest] +platforms = ["win32", "linux", "darwin"] +apt_dependencies = ["xclip"] diff --git a/stubs/pyperclip/pyperclip/__init__.pyi b/stubs/pyperclip/pyperclip/__init__.pyi index 2213d6a969cb..542a97f3143e 100644 --- a/stubs/pyperclip/pyperclip/__init__.pyi +++ b/stubs/pyperclip/pyperclip/__init__.pyi @@ -1,8 +1,7 @@ __all__ = ["copy", "paste", "set_clipboard", "determine_clipboard"] from collections.abc import Callable -from typing import Any, Literal, TypeAlias, Protocol - +from typing import Any, Literal, Protocol, TypeAlias class PyperclipException(RuntimeError): ... @@ -11,22 +10,22 @@ class PyperclipWindowsException(PyperclipException): class PyperclipTimeoutException(PyperclipException): ... - -class WinDLLUser32Function(Protocol): +class _WinDLLUser32Function(Protocol): def __call__(self, *args: Any) -> Any: ... - # Wrapper for ctypes calls, should not be exposed to the developer class CheckedCall: - def __init__(self, f: WinDLLUser32Function) -> None: ... + def __init__(self, f: _WinDLLUser32Function) -> None: ... def __call__(self, *args: Any): ... def __setattr__(self, key: str, value: Any) -> None: ... -ClipboardMechanismName: TypeAlias = Literal["pbcopy", "pyobjc", "qt", "xclip", "xsel", "wl-clipboard", "klipper", "windows", "no"] -ClipboardCopyMechanism: TypeAlias = Callable[[str], None] -ClipboardPasteMechanism: TypeAlias = Callable[[], str] +_ClipboardMechanismName: TypeAlias = Literal[ + "pbcopy", "pyobjc", "qt", "xclip", "xsel", "wl-clipboard", "klipper", "windows", "no" +] +_ClipboardCopyMechanism: TypeAlias = Callable[[str], None] +_ClipboardPasteMechanism: TypeAlias = Callable[[], str] def copy(text: str) -> None: ... def paste() -> str: ... -def set_clipboard(clipboard: ClipboardMechanismName) -> None: ... -def determine_clipboard() -> tuple[ClipboardCopyMechanism, ClipboardPasteMechanism]: ... +def set_clipboard(clipboard: _ClipboardMechanismName) -> None: ... +def determine_clipboard() -> tuple[_ClipboardCopyMechanism, _ClipboardPasteMechanism]: ... From 73fdc675399b4feee5e5d12f2bf6d2c6f1c6ed65 Mon Sep 17 00:00:00 2001 From: Xiddoc Date: Sat, 15 Feb 2025 15:00:46 +0200 Subject: [PATCH 6/9] Pyperclip's main file is irrelevant --- stubs/clipboard/METADATA.toml | 3 ++- stubs/pyperclip/@tests/stubtest_allowlist.txt | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 stubs/pyperclip/@tests/stubtest_allowlist.txt diff --git a/stubs/clipboard/METADATA.toml b/stubs/clipboard/METADATA.toml index 1091178a5a77..7705e0054f66 100644 --- a/stubs/clipboard/METADATA.toml +++ b/stubs/clipboard/METADATA.toml @@ -1,6 +1,7 @@ version = "0.0.*" upstream_repository = "https://github.com/terryyin/clipboard" -requires = ["pyperclip"] +requires = ["types-pyperclip"] +partial_stub = true [tool.stubtest] platforms = ["win32", "linux", "darwin"] diff --git a/stubs/pyperclip/@tests/stubtest_allowlist.txt b/stubs/pyperclip/@tests/stubtest_allowlist.txt new file mode 100644 index 000000000000..096a897229c8 --- /dev/null +++ b/stubs/pyperclip/@tests/stubtest_allowlist.txt @@ -0,0 +1 @@ +pyperclip.__main__ From 592ba1ef676d0831a852d987b817f27a8353d0f1 Mon Sep 17 00:00:00 2001 From: Xiddoc Date: Sat, 15 Feb 2025 15:20:26 +0200 Subject: [PATCH 7/9] Fixed type for CheckedCall --- stubs/clipboard/METADATA.toml | 4 ++-- stubs/pyperclip/pyperclip/__init__.pyi | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/stubs/clipboard/METADATA.toml b/stubs/clipboard/METADATA.toml index 7705e0054f66..2d5301dfb33d 100644 --- a/stubs/clipboard/METADATA.toml +++ b/stubs/clipboard/METADATA.toml @@ -1,8 +1,8 @@ version = "0.0.*" upstream_repository = "https://github.com/terryyin/clipboard" -requires = ["types-pyperclip"] -partial_stub = true +requires = ["pyperclip"] [tool.stubtest] +skip = true # Dependent on pyperclip's types being uploaded. platforms = ["win32", "linux", "darwin"] stubtest_requirements = ["pyperclip"] diff --git a/stubs/pyperclip/pyperclip/__init__.pyi b/stubs/pyperclip/pyperclip/__init__.pyi index 542a97f3143e..1b16e3de8f85 100644 --- a/stubs/pyperclip/pyperclip/__init__.pyi +++ b/stubs/pyperclip/pyperclip/__init__.pyi @@ -1,7 +1,8 @@ __all__ = ["copy", "paste", "set_clipboard", "determine_clipboard"] from collections.abc import Callable -from typing import Any, Literal, Protocol, TypeAlias +from typing import Any, Literal, Protocol +from typing_extensions import TypeAlias class PyperclipException(RuntimeError): ... @@ -16,7 +17,7 @@ class _WinDLLUser32Function(Protocol): # Wrapper for ctypes calls, should not be exposed to the developer class CheckedCall: def __init__(self, f: _WinDLLUser32Function) -> None: ... - def __call__(self, *args: Any): ... + def __call__(self, *args: Any) -> Any: ... def __setattr__(self, key: str, value: Any) -> None: ... _ClipboardMechanismName: TypeAlias = Literal[ From 321fdb537c777a5ecd37543488c54ea05eb44c04 Mon Sep 17 00:00:00 2001 From: Xiddoc Date: Sat, 15 Feb 2025 18:40:27 +0200 Subject: [PATCH 8/9] Move clipboard stubs to new PR --- stubs/clipboard/METADATA.toml | 8 -------- stubs/clipboard/clipboard.pyi | 1 - 2 files changed, 9 deletions(-) delete mode 100644 stubs/clipboard/METADATA.toml delete mode 100644 stubs/clipboard/clipboard.pyi diff --git a/stubs/clipboard/METADATA.toml b/stubs/clipboard/METADATA.toml deleted file mode 100644 index 2d5301dfb33d..000000000000 --- a/stubs/clipboard/METADATA.toml +++ /dev/null @@ -1,8 +0,0 @@ -version = "0.0.*" -upstream_repository = "https://github.com/terryyin/clipboard" -requires = ["pyperclip"] - -[tool.stubtest] -skip = true # Dependent on pyperclip's types being uploaded. -platforms = ["win32", "linux", "darwin"] -stubtest_requirements = ["pyperclip"] diff --git a/stubs/clipboard/clipboard.pyi b/stubs/clipboard/clipboard.pyi deleted file mode 100644 index 86e0b96acaca..000000000000 --- a/stubs/clipboard/clipboard.pyi +++ /dev/null @@ -1 +0,0 @@ -from pyperclip import copy as copy, paste as paste From b6b14905ced67e58c27e580def43729f4c4a2ffb Mon Sep 17 00:00:00 2001 From: Xiddoc Date: Sun, 16 Feb 2025 22:22:27 +0200 Subject: [PATCH 9/9] Drop stubs for CheckedCall and added is_available --- stubs/pyperclip/pyperclip/__init__.pyi | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/stubs/pyperclip/pyperclip/__init__.pyi b/stubs/pyperclip/pyperclip/__init__.pyi index 1b16e3de8f85..4d2947e849f7 100644 --- a/stubs/pyperclip/pyperclip/__init__.pyi +++ b/stubs/pyperclip/pyperclip/__init__.pyi @@ -1,7 +1,7 @@ __all__ = ["copy", "paste", "set_clipboard", "determine_clipboard"] from collections.abc import Callable -from typing import Any, Literal, Protocol +from typing import Literal from typing_extensions import TypeAlias class PyperclipException(RuntimeError): ... @@ -11,15 +11,6 @@ class PyperclipWindowsException(PyperclipException): class PyperclipTimeoutException(PyperclipException): ... -class _WinDLLUser32Function(Protocol): - def __call__(self, *args: Any) -> Any: ... - -# Wrapper for ctypes calls, should not be exposed to the developer -class CheckedCall: - def __init__(self, f: _WinDLLUser32Function) -> None: ... - def __call__(self, *args: Any) -> Any: ... - def __setattr__(self, key: str, value: Any) -> None: ... - _ClipboardMechanismName: TypeAlias = Literal[ "pbcopy", "pyobjc", "qt", "xclip", "xsel", "wl-clipboard", "klipper", "windows", "no" ] @@ -30,3 +21,4 @@ def copy(text: str) -> None: ... def paste() -> str: ... def set_clipboard(clipboard: _ClipboardMechanismName) -> None: ... def determine_clipboard() -> tuple[_ClipboardCopyMechanism, _ClipboardPasteMechanism]: ... +def is_available() -> bool: ...