pyperclip reads and writes the system clipboard from Python. pip install pyperclip. Copy: import pyperclip; pyperclip.copy("hello world"). Paste: text = pyperclip.paste(). Error: from pyperclip import PyperclipException — raised when no clipboard mechanism found (headless Linux without xclip/xsel). Platform: macOS uses pbcopy/pbpaste, Windows uses ctypes win32 clipboard API, Linux uses xclip or xsel if available. Install xclip: apt install xclip. Fallback: try: pyperclip.copy(text); except PyperclipException: print(text). waitForNewPaste: pyperclip.waitForNewPaste() — blocks until clipboard changes, returns new content. pyperclip.waitForPaste() — blocks until clipboard is non-empty. Determine: pyperclip.determine_clipboard() — returns copy/paste fn pair. setClipboard: pyperclip.setclipboard("pbcopy") — force a specific mechanism. CLI copy: pipe output to clipboard — result = run_command(); pyperclip.copy(result); print("Copied!"). Template: generate code snippet, copy to clipboard for pasting into editor. Argparse: --copy flag that calls pyperclip.copy(output) after generating. Clipboard history: store sequence of pyperclip.paste() results. Multi-copy: copy formatted table, JSON, or CSV — paste into spreadsheet or terminal. Claude Code generates pyperclip copy/paste helpers, CLI copy flags, and clipboard pipeline utilities.
CLAUDE.md for pyperclip
## pyperclip Stack
- Version: pyperclip >= 1.8 | pip install pyperclip
- Copy: pyperclip.copy(text) — writes to system clipboard
- Paste: text = pyperclip.paste() — reads from system clipboard
- Error: catch PyperclipException on headless Linux without xclip/xsel
- Wait: pyperclip.waitForNewPaste() — blocks until clipboard changes
- CLI: add --copy flag that calls pyperclip.copy(output) after generating
- Linux: install xclip (apt install xclip) or xsel for clipboard support
pyperclip Clipboard Pipeline
# app/clipboard.py — pyperclip copy/paste, CLI --copy flag, and clipboard utilities
from __future__ import annotations
import json
import sys
import time
from typing import Any, Callable
try:
import pyperclip
from pyperclip import PyperclipException
_PYPERCLIP_AVAILABLE = True
except ImportError:
_PYPERCLIP_AVAILABLE = False
PyperclipException = Exception
# ─────────────────────────────────────────────────────────────────────────────
# 1. Safe copy/paste wrappers
# ─────────────────────────────────────────────────────────────────────────────
def copy(text: str, silent: bool = False) -> bool:
"""
Copy text to the system clipboard.
Returns True on success, False when no clipboard mechanism is available
(headless Linux without xclip/xsel, SSH sessions without X forwarding).
"""
if not _PYPERCLIP_AVAILABLE:
return False
try:
pyperclip.copy(text)
if not silent:
char_count = len(text)
line_count = text.count("\n") + 1
print(f" Copied {char_count} chars ({line_count} lines) to clipboard.")
return True
except PyperclipException as e:
if not silent:
print(f" Clipboard unavailable: {e}", file=sys.stderr)
return False
def paste() -> str | None:
"""
Read the current clipboard content.
Returns None if clipboard is unavailable or empty.
"""
if not _PYPERCLIP_AVAILABLE:
return None
try:
return pyperclip.paste() or None
except PyperclipException:
return None
def copy_or_print(text: str, copy_flag: bool = False) -> None:
"""
Utility used by CLI commands: copy if --copy passed, otherwise print.
This is the canonical pattern for CLI tools that generate text output.
"""
if copy_flag:
ok = copy(text, silent=True)
if ok:
print(f"✓ Copied to clipboard ({len(text)} chars)")
else:
# Fall back to printing when clipboard isn't available
print(text)
else:
print(text)
# ─────────────────────────────────────────────────────────────────────────────
# 2. Formatted copy helpers
# ─────────────────────────────────────────────────────────────────────────────
def copy_json(obj: Any, indent: int = 2, copy_flag: bool = True) -> str:
"""Serialize obj to JSON and copy to clipboard."""
text = json.dumps(obj, indent=indent, ensure_ascii=False, default=str)
copy_or_print(text, copy_flag)
return text
def copy_table_csv(
rows: list[dict],
columns: list[str] | None = None,
copy_flag: bool = True,
) -> str:
"""
Format a list of dicts as CSV and optionally copy.
Paste directly into Excel or Google Sheets.
"""
import csv, io
columns = columns or (list(rows[0].keys()) if rows else [])
buf = io.StringIO()
writer = csv.DictWriter(buf, fieldnames=columns, extrasaction="ignore")
writer.writeheader()
writer.writerows(rows)
text = buf.getvalue()
copy_or_print(text, copy_flag)
return text
def copy_markdown_table(
rows: list[dict],
columns: list[str] | None = None,
copy_flag: bool = True,
) -> str:
"""Format a list of dicts as a Markdown table and optionally copy."""
if not rows:
return ""
columns = columns or list(rows[0].keys())
widths = {col: max(len(col), max(len(str(r.get(col, ""))) for r in rows)) for col in columns}
header = "| " + " | ".join(f"{c:<{widths[c]}}" for c in columns) + " |"
sep = "| " + " | ".join("-" * widths[c] for c in columns) + " |"
body = "\n".join(
"| " + " | ".join(f"{str(r.get(c,'')):<{widths[c]}}" for c in columns) + " |"
for r in rows
)
text = f"{header}\n{sep}\n{body}"
copy_or_print(text, copy_flag)
return text
# ─────────────────────────────────────────────────────────────────────────────
# 3. Clipboard wait / watch
# ─────────────────────────────────────────────────────────────────────────────
def wait_for_new_paste(timeout: float = 30.0, prompt: str = "") -> str | None:
"""
Block until the clipboard changes and return the new content.
pyperclip.waitForNewPaste() polls the clipboard until it changes.
timeout: how long to wait in seconds (0 = indefinite).
"""
if not _PYPERCLIP_AVAILABLE:
return None
if prompt:
print(prompt)
try:
if timeout > 0:
# waitForNewPaste doesn't support timeout — implement with thread
import threading
result: list[str] = []
exc: list[Exception] = []
def _wait():
try:
result.append(pyperclip.waitForNewPaste())
except Exception as e:
exc.append(e)
t = threading.Thread(target=_wait, daemon=True)
t.start()
t.join(timeout=timeout)
if exc:
raise exc[0]
return result[0] if result else None
else:
return pyperclip.waitForNewPaste()
except PyperclipException:
return None
def watch_clipboard(
callback: Callable[[str], None],
interval: float = 0.5,
max_events: int = 0,
) -> None:
"""
Poll clipboard every `interval` seconds and call callback on changes.
Useful for clipboard-driven automation tools.
max_events=0 → run forever (until KeyboardInterrupt).
"""
if not _PYPERCLIP_AVAILABLE:
raise RuntimeError("pyperclip is not available")
last = paste() or ""
seen = 0
try:
while True:
current = paste() or ""
if current != last and current:
last = current
callback(current)
seen += 1
if max_events and seen >= max_events:
break
time.sleep(interval)
except KeyboardInterrupt:
pass
# ─────────────────────────────────────────────────────────────────────────────
# 4. argparse --copy flag integration
# ─────────────────────────────────────────────────────────────────────────────
def add_copy_argument(parser) -> None:
"""
Add a --copy / -c flag to an argparse.ArgumentParser.
The flag tells the tool to copy its output to the clipboard.
"""
parser.add_argument(
"--copy", "-c",
action="store_true",
default=False,
help="Copy output to clipboard instead of printing",
)
# ─────────────────────────────────────────────────────────────────────────────
# 5. Clipboard history (session-level)
# ─────────────────────────────────────────────────────────────────────────────
class ClipboardHistory:
"""
Record a sequence of clipboard snapshots.
Useful for building tools that process a series of pasted values.
"""
def __init__(self, max_size: int = 50) -> None:
self._history: list[str] = []
self._max = max_size
def snapshot(self) -> str | None:
"""Take a snapshot of the current clipboard."""
text = paste()
if text and (not self._history or self._history[-1] != text):
if len(self._history) >= self._max:
self._history.pop(0)
self._history.append(text)
return text
def last(self) -> str | None:
return self._history[-1] if self._history else None
def all(self) -> list[str]:
return list(self._history)
def clear(self) -> None:
self._history.clear()
# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
print("=== Basic copy/paste ===")
ok = copy("Hello from pyperclip!")
if ok:
text = paste()
print(f" Read back: {text!r}")
print("\n=== Copy JSON ===")
data = {"name": "Alice", "score": 95, "tags": ["python", "cli"]}
copy_json(data, copy_flag=True)
print("\n=== Copy Markdown table ===")
rows = [
{"tool": "pyperclip", "version": "1.8", "use": "clipboard"},
{"tool": "colorama", "version": "0.4", "use": "colors"},
{"tool": "rich", "version": "13", "use": "terminal UI"},
]
copy_markdown_table(rows, copy_flag=True)
print("\n=== Copy CSV ===")
copy_table_csv(rows, copy_flag=True)
print("\n=== Clipboard available ===")
print(f" pyperclip available: {_PYPERCLIP_AVAILABLE}")
# Clipboard watch demo (fires once then exits due to max_events=1)
# Uncomment to test interactively:
# print("\n=== Watching clipboard (copy something within 5 seconds) ===")
# watch_clipboard(lambda t: print(f" New clipboard: {t[:80]}"), max_events=1)
For the subprocess pbcopy/pbpaste alternative — calling subprocess.run(["pbcopy"], input=text.encode()) works on macOS but fails on Linux and Windows, requiring platform-specific branching; pyperclip handles all three platforms with one API, using pbcopy/pbpaste on macOS, the Win32 clipboard API on Windows, and xclip/xsel on Linux, so the same pyperclip.copy(text) call works everywhere without sys.platform conditionals. For the tkinter.Tk().clipboard_get() alternative — tkinter can access the clipboard but requires a display connection and spinning up a Tk root window, which fails in headless environments and adds startup latency; pyperclip is a lightweight wrapper that uses native clipboard utilities directly without a GUI framework dependency. The Claude Skills 360 bundle includes pyperclip skill sets covering pyperclip.copy() and pyperclip.paste(), safe copy() wrapper with PyperclipException handling, copy_or_print() for —copy CLI flag pattern, copy_json() for JSON output, copy_table_csv() and copy_markdown_table() for formatted table output, wait_for_new_paste() with timeout, watch_clipboard() polling watcher, ClipboardHistory session recorder, and add_copy_argument() argparse integration. Start with the free tier to try clipboard integration code generation.