mrkeyoor.com_
Sun 20 Sept 11:45 UTC
PyPIUtilsupdated 20 Sept 2026

pyperclip review

Pyperclip 1.11.0 gave our Python 3.12 sandbox a two-function bridge to the host's plain-text clipboard: `copy()` writes text and `paste()` reads it. Our install used 1 MB and brought in no dependencies, but that small wheel is only the dispatcher. Windows calls its clipboard API, macOS uses PyObjC or `pbcopy` and `pbpaste`, and Linux looks for a Wayland, X11, KDE, or Qt mechanism already present on the machine. The release commit for 1.11.0 replaced `setup.py` with `pyproject.toml`, refreshed classifiers through Python 3.14, and bumped the runtime version. Its clipboard code stayed unchanged in that commit.

Verdict

In our sandbox, pyperclip 1.11.0 installed in 0.2 seconds, occupied 1 MB as one package, imported in 0.22 seconds, and produced 0 pip-audit findings. Install it for plain-text desktop utilities that can print a fallback, and use an environment-specific API when a missing display or richer clipboard format must never be a surprise.

We installed it

Lab card: what happened when we installed pyperclipScreenshot of pyperclip documentation
Install✓ · 0.2s1 package on disk · 1 MB
Importimport pyperclip in 0.22s · pure Python
Known vulns0(pip-audit)

Answers from our run

Does pyperclip install cleanly?

Yes. In a fresh container with an empty cache, pip install pyperclip finished in 0.2s, leaving 1 package and 1 MB on disk. pip-audit reported no known vulnerabilities.

What does pyperclip need to run?

Python 3.x, and nothing compiled: it is pure Python. In our run import pyperclip succeeded in 0.22s.

pyperclip or pyclip: which should you use?

Pick pyclip when the same cross-platform wrapper must move binary clipboard data as well as text. In our sandbox, pyperclip 1.11.0 installed in 0.2 seconds, occupied 1 MB as one package, imported in 0.22 seconds, and produced 0 pip-audit findings.

When should you not use pyperclip?

The code runs mainly through SSH, CI, or a headless container. Pyperclip 1.11.0 has no OSC 52 path, and remote-terminal support remains an unmerged pull request.

API stability4/5Pyperclip 1.11.0 still centers its public surface on `copy()`, `paste()`, backend selection, and the exception raised when no mechanism works. The release commit changed packaging files and the version constant without touching clipboard behavior. A perfect score would ignore a real 1.x break: 2 documented wait functions disappeared from the installed module in version 1.9.0, yet the live documentation still presents them as available.
Docs2/5The live Pyperclip documentation shows `waitForPaste()` and `waitForNewPaste()`, but neither name exists in version 1.11.0. Its Linux repair list also recommends GTK even though the source explicitly says PyGObject is unsupported and has no GTK backend. The README explains the basic 2-call API, while backend priority, WSL behavior, lazy detection, and the `PATH` security warning are left to source readers.
Maintenance2/5PyPI received pyperclip 1.11.0 on September 26, 2025, and GitHub shows the last repository push on the same date. The project is not archived, but it has no Git tags or GitHub releases for that version. GitHub currently counts 116 open issues and 20 open pull requests. Fixes for OSC 52, early `is_available()` detection, Android, Qt fallback handling, and type stubs were still open when we checked on September 16, 2026.
Ecosystem4/5Pyperclip recorded 16,391,611 PyPI downloads in the latest week, and the GitHub repository has 1,843 stars. Version 1.11.0 covers native Windows calls, macOS pasteboard paths, WSL, Wayland, X11, KDE, and Qt behind the same small API. That range is useful for desktop scripts. It does not extend to rich formats or headless terminal protocols, and most Unix paths depend on programs or GUI bindings outside the Python install.

Use it if

  • A desktop command should copy a generated token, path, or URL after showing the same value in the terminal as a fallback.
  • One Python utility must expose the same `copy()` and `paste()` calls on Windows, macOS, and Linux while accepting different native backends underneath.
  • Your Linux workstation image already includes `wl-clipboard`, `xclip`, `xsel`, Klipper with `qdbus`, or a usable Qt binding.
  • A 1 MB, dependency-free install matters more than support for formatted clipboard data, events, or clipboard history.
Skip it if

Setup reality

We installed pyperclip 1.11.0 without a cache in an unprivileged Python 3.12 Bookworm container on August 22, 2026. pip finished in 0.2 seconds. The environment held one installed package using 1 MB, and pyperclip declared 0 direct dependencies. pip-audit found 0 known vulnerabilities. The pure-Python distribution imported in 0.22 seconds, carries a BSD license, states no minimum Python version, and does not ship a py.typed marker.

There are no credentials or config files. Version 1.11.0 talks to Windows directly and can use PyObjC or the built-in pasteboard commands on macOS. WSL calls clip.exe for writes and PowerShell for reads. Linux is where setup moves outside pip: Wayland needs both wl-copy and wl-paste. X11 needs DISPLAY plus xclip, xsel, Klipper with qdbus, QtPy, or PyQt5. The wheel installs none of those helpers.

The 0.22-second import succeeded because backend detection is lazy. Pyperclip waits for the first copy() or paste() call, chooses a mechanism, then replaces its module-level wrapper functions. A headless import can therefore look healthy until that first operation raises PyperclipException. is_available() also returns false before selection, so it is a poor preflight check. Command backends are resolved through PATH. The source warns that a planted executable would run with the Python process's permissions.

Pyperclip 1.11.0 converts values passed to copy() with str() and returns text from paste(). It has no wait helper despite the examples on Read the Docs. Polling is application code, and a 0.1-second loop can launch a Unix process on every read. set_clipboard() swaps global module functions, so pick a backend during startup instead of changing it while worker threads are active. Clipboard ownership still belongs to the operating system, which means another application can replace the value immediately after a successful write.

Patterns

Write text, then read the current clipboard copy-and-read-text

import pyperclip

pyperclip.copy("build 184 is ready")
current = pyperclip.paste()
print(current)

The first call chooses a backend for this process. The value read later may come from another application that wrote to the clipboard in between.

Keep a command useful without a display print-fallback

import sys
import pyperclip

def publish(value: str) -> None:
    print(value)
    try:
        pyperclip.copy(value)
    except pyperclip.PyperclipException as exc:
        print("clipboard skipped: {}".format(exc), file=sys.stderr)

A successful import does not exercise the clipboard. In a headless session, the exception usually arrives on the first copy or paste operation.

Resolve a backend before accepting clipboard work probe-backend

import pyperclip

copy_text, paste_text = pyperclip.determine_clipboard()
if not copy_text:
    raise RuntimeError("no clipboard mechanism found")

copy_text("ready")

`determine_clipboard()` returns two callables and leaves the module's lazy wrappers alone. The unavailable placeholder evaluates to false.

Select wl-clipboard explicitly pin-wayland

from shutil import which
import pyperclip

required = ("wl-copy", "wl-paste")
if any(which(command) is None for command in required):
    raise RuntimeError("wl-clipboard is missing")

pyperclip.set_clipboard("wl-clipboard")
pyperclip.copy("ready")

Version 1.11.0 does not install `wl-copy` or `wl-paste`. Both commands must resolve through `PATH` before this backend can copy and read.

Write to the X11 primary selection use-x11-primary

import pyperclip

pyperclip.set_clipboard("xclip")
pyperclip.copy("selected text", primary=True)
selection = pyperclip.paste(primary=True)

The `primary` argument is available on the xclip and xsel backend functions. Call `set_clipboard()` first because the initial lazy wrapper accepts only the text argument.

Put valid JSON on the clipboard copy-json

import json
import pyperclip

payload = {"job": 184, "state": "ready"}
serialized = json.dumps(payload, indent=2, sort_keys=True)
pyperclip.copy(serialized)

`copy()` applies `str()` to non-string values. Serialize the object first or the clipboard will contain Python representation syntax instead of JSON.

Copy a command's standard output pipe-to-clipboard

generate-release-notes | python -m pyperclip --copy

The version 1.11.0 module command reads standard input through EOF when `--copy` has no following text argument.

Redirect clipboard text into a file paste-to-file

python -m pyperclip --paste > clipboard.txt

The paste command writes the clipboard value to standard output and does not append a newline. Redirection keeps the backend's text unchanged.

Test clipboard code without touching the desktop mock-clipboard

from unittest.mock import patch

with patch("pyperclip.copy") as copy_spy:
    export_code("row-184")

copy_spy.assert_called_once_with("row-184")

Patching `pyperclip.copy` before the application call prevents lazy detection from starting an X11, Wayland, Qt, or native clipboard path.

Poll for changed text with a deadline wait-for-change

from time import monotonic, sleep
import pyperclip

def wait_for_change(previous: str, seconds: float = 5.0) -> str:
    deadline = monotonic() + seconds
    while monotonic() < deadline:
        value = pyperclip.paste()
        if value != previous:
            return value
        sleep(0.2)
    raise TimeoutError("clipboard stayed unchanged")

Pyperclip 1.11.0 provides no wait function or change event. With a command backend, each 0.2-second check may start another process.

Move a clipboard read off an async loop avoid-blocking-loop

import asyncio
import pyperclip

async def read_clipboard() -> str:
    return await asyncio.to_thread(pyperclip.paste)

`asyncio.to_thread()` requires Python 3.9 or newer. Pyperclip 1.11.0 exposes synchronous backends, so this call keeps their subprocess or Windows retry work away from unrelated coroutines.

Clear only the value your code copied clear-if-unchanged

import pyperclip

pyperclip.copy(secret)
try:
    send_secret()
finally:
    if pyperclip.paste() == secret:
        pyperclip.copy("")

The equality check preserves a newer value copied by the user. Clipboard managers may still retain the original secret in their history.

Alternatives

PackageRegistryPick it when
pyclipPyPIPick it when the same cross-platform wrapper must move binary clipboard data as well as text.
klembordPyPIPick it for HTML or named formats on Windows and Linux X11 after confirming that its narrower platform list fits the deployment.
pywin32PyPIUse the Windows extensions when native format IDs, ownership, and clipboard messages are part of the job.
PySide6PyPIUse Qt's MIME-aware clipboard when the application already carries PySide6 for its interface.

More utils guides

lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.