Cross-platform clipboard access with zero external dependencies. No xclip or xsel needed on Linux.
Project description
pyxclip
Cross-platform clipboard access with zero external dependencies. No xclip or xsel needed on Linux. Built with Rust (PyO3 + arboard) for speed and reliability.
Installation
pip install pyxclip
Works with Python 3.8 through 3.14. No C compiler or system packages required.
Quick Start
import pyxclip
pyxclip.copy("Hello, world!")
text = pyxclip.paste()
print(text) # Hello, world!
That's the whole API. Three functions: copy(), paste(), and clear(). Copy figures out what to do based on the type you pass. Paste returns whatever is on the clipboard.
Text Operations
Copy and paste strings, unicode, multiline text, even empty strings.
import pyxclip
# Basic text
pyxclip.copy("Hello, world!")
print(pyxclip.paste()) # Hello, world!
# Unicode and emoji
pyxclip.copy("cafe\u0301, na\u00efvet\u00e9, \U0001f600")
print(pyxclip.paste()) # cafe, naiveté, 😀
# Multiline text
blocks = """First line
Second line
Third line"""
pyxclip.copy(blocks)
print(pyxclip.paste())
# First line
# Second line
# Third line
# Empty string clears to empty text
pyxclip.copy("")
print(pyxclip.paste()) # (empty string)
Clear the Clipboard
Pass None to copy() or call clear().
import pyxclip
# Either way works
pyxclip.copy(None)
pyxclip.clear()
# Pasting after clearing raises ClipboardError
try:
pyxclip.paste()
except pyxclip.ClipboardError:
print("Clipboard is empty")
Image Operations
Copy images by passing a (width, height, pixels) tuple where pixels is raw RGBA data, 4 bytes per pixel, row-major order. Paste returns a dict with "width", "height", and "bytes" keys.
import pyxclip
# Create a 4x4 red square
width, height = 4, 4
pixels = b"\xff\x00\x00\xff" * (width * height) # RGBA: red, fully opaque
pyxclip.copy((width, height, pixels))
# Paste the image back
result = pyxclip.paste()
print(type(result)) # <class 'dict'>
print(result["width"]) # 4
print(result["height"]) # 4
print(len(result["bytes"])) # 64 (4 * 4 * 4 bytes)
# Save pasted image to a PNG file
from PIL import Image
result = pyxclip.paste()
img = Image.frombytes("RGBA", (result["width"], result["height"]), result["bytes"])
img.save("screenshot.png")
File Operations
Copy file paths to the clipboard as a single Path or a list. Paste returns a list of strings.
import pyxclip
from pathlib import Path
# Single file
pyxclip.copy(Path("/tmp/report.pdf"))
# Multiple files
files = [Path("/tmp/report.pdf"), Path.home() / "photos" / "vacation.jpg"]
pyxclip.copy(files)
# Paste returns a list
pasted = pyxclip.paste()
print(type(pasted)) # <class 'list'>
print(pasted) # ['/tmp/report.pdf', '/home/user/photos/vacation.jpg']
str vs Path — why it matters
str is always treated as text, never as a file path. This is intentional:
import pyxclip
from pathlib import Path
pyxclip.copy("/some/path.txt")
print(pyxclip.paste()) # "/some/path.txt" — copied as text
pyxclip.copy(Path("/some/path.txt"))
# — copied as file reference (if file exists)
If you have a string that represents a file path, wrap it in Path:
pyxclip.copy(Path(my_string_path))
Error messages
File copy errors are specific about what went wrong:
import pyxclip
from pathlib import Path
try:
pyxclip.copy(Path("/does/not/exist.txt"))
except pyxclip.ClipboardError as e:
print(e)
# "Failed to copy file paths to clipboard: one or more files may not exist
# or are inaccessible. All paths must point to existing files or directories."
File path copy succeeds on all desktop platforms (Windows, macOS, Linux). However, pasting files into a file manager depends on your desktop environment. pyxclip writes the standard text/uri-list format — whether the receiving app reads it is up to that app.
If copy() succeeds but pasting into a specific app doesn't work, the issue is with that app's clipboard support — not pyxclip.
Error Handling
All clipboard failures raise ClipboardError, a subclass of RuntimeError.
import pyxclip
# Catch any clipboard failure
try:
pyxclip.paste()
except pyxclip.ClipboardError as e:
print(f"Failed: {e}")
# Detect headless environments before trying
import os
def clipboard_available() -> bool:
if os.environ.get("DISPLAY") or os.environ.get("WAYLAND_DISPLAY"):
return True
if os.name == "nt" or sys.platform == "darwin":
return True
return False
if clipboard_available():
pyxclip.copy("works!")
else:
print("No clipboard in this environment")
Common errors:
"No display server available (headless?)"-- no display set on Linux"Clipboard is empty or contains incompatible data"-- nothing readable"Clipboard is held by another process; retry later"-- transient lock
Practical Examples
Copy the result of a script to clipboard
import pyxclip
import json
data = {"status": "ok", "items": [1, 2, 3]}
pyxclip.copy(json.dumps(data, indent=2))
# Now Ctrl+V in any editor pastes formatted JSON
Pipe data through the clipboard in shell scripts
# Sort lines from clipboard and put them back
python3 -c "
import pyxclip
lines = pyxclip.paste().strip().split('\n')
pyxclip.copy('\n'.join(sorted(set(lines))))
"
# Reverse the clipboard content
python3 -c "
import pyxclip
t = pyxclip.paste()
pyxclip.copy(t[::-1])
"
Clipboard-based communication between scripts
# producer.py
import pyxclip
import time
for i in range(5):
pyxclip.copy(f"task-{i}")
time.sleep(1)
# consumer.py
import pyxclip
last = None
while True:
current = pyxclip.paste()
if current != last:
print(f"New item: {current}")
last = current
Paste clipboard content into a file
import pyxclip
content = pyxclip.paste()
with open("clipboard_dump.txt", "w") as f:
f.write(content)
print(f"Saved {len(content)} characters")
Copy an API response to clipboard
import pyxclip
import urllib.request
resp = urllib.request.urlopen("https://httpbin.org/get")
data = resp.read().decode()
pyxclip.copy(data)
print("API response copied to clipboard")
Quick notes manager
import pyxclip
from datetime import datetime
# Append a timestamped note
note = pyxclip.paste()
with open("notes.txt", "a") as f:
f.write(f"[{datetime.now():%Y-%m-%d %H:%M}] {note}\n")
print("Note saved")
Copy a URL from a script
import pyxclip
url = "https://github.com/abbazs/pyxclip"
pyxclip.copy(url)
print(f"Copied: {url} -- paste in browser")
Copy source code to clipboard
import pyxclip
code = '''
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return a
'''
pyxclip.copy(code.strip())
Grab and re-copy clipboard text with modifications
import pyxclip
text = pyxclip.paste()
pyxclip.copy(text.upper()) # or .lower(), .strip(), .replace(...)
print("Text transformed in clipboard")
Type Signatures
def copy(data: None | str | tuple[int, int, bytes] | os.PathLike[str] | os.PathLike[bytes] | list[os.PathLike[str] | str], /) -> None: ...
def paste() -> str | dict[str, object] | list[str]: ...
def clear() -> None: ...
class ClipboardError(RuntimeError): ...
Platform Support
| Platform | Backend | Notes |
|---|---|---|
| Linux | X11 / Wayland | No xclip/xsel. Wayland uses wayland-data-control. |
| macOS | NSPasteboard | System framework. |
| Windows | Win32 | System API. |
On headless Linux (no DISPLAY, no WAYLAND_DISPLAY), all operations raise ClipboardError.
How It Works
A single Rust extension module compiled with PyO3, using arboard for native clipboard access. No Python dependencies beyond the compiled wheel.
License
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyxclip-0.2.3.tar.gz.
File metadata
- Download URL: pyxclip-0.2.3.tar.gz
- Upload date:
- Size: 17.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3fbb12b9e33c46c143d5a19312599f635b1db97e828ea3174934ebbfb3acb557
|
|
| MD5 |
39566c8d3e391b479ff156d4ff31e5fd
|
|
| BLAKE2b-256 |
967337811428a0762c97c688864f1115fb83c4428a725308c83b0f48f3912570
|
Provenance
The following attestation bundles were made for pyxclip-0.2.3.tar.gz:
Publisher:
publish.yml on abbazs/pyxclip
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyxclip-0.2.3.tar.gz -
Subject digest:
3fbb12b9e33c46c143d5a19312599f635b1db97e828ea3174934ebbfb3acb557 - Sigstore transparency entry: 1155015078
- Sigstore integration time:
-
Permalink:
abbazs/pyxclip@4bdde3dbfdaa14d09cf9cd2f34584ca59acec64d -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/abbazs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4bdde3dbfdaa14d09cf9cd2f34584ca59acec64d -
Trigger Event:
push
-
Statement type:
File details
Details for the file pyxclip-0.2.3-cp313-abi3-win_amd64.whl.
File metadata
- Download URL: pyxclip-0.2.3-cp313-abi3-win_amd64.whl
- Upload date:
- Size: 292.2 kB
- Tags: CPython 3.13+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7fe21acafdb3425feaf9f4d55ea54a464ebad67ae9eee4311ea5604641ba2c09
|
|
| MD5 |
a345e499bef37f661e2898bf960bbac4
|
|
| BLAKE2b-256 |
ac4a2f1ba1573cda6d47197658b917c043aad576f60a0af45ab3979ca7595ff9
|
Provenance
The following attestation bundles were made for pyxclip-0.2.3-cp313-abi3-win_amd64.whl:
Publisher:
publish.yml on abbazs/pyxclip
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyxclip-0.2.3-cp313-abi3-win_amd64.whl -
Subject digest:
7fe21acafdb3425feaf9f4d55ea54a464ebad67ae9eee4311ea5604641ba2c09 - Sigstore transparency entry: 1155015090
- Sigstore integration time:
-
Permalink:
abbazs/pyxclip@4bdde3dbfdaa14d09cf9cd2f34584ca59acec64d -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/abbazs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4bdde3dbfdaa14d09cf9cd2f34584ca59acec64d -
Trigger Event:
push
-
Statement type:
File details
Details for the file pyxclip-0.2.3-cp313-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: pyxclip-0.2.3-cp313-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 705.8 kB
- Tags: CPython 3.13+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a3b38b03a41145d532d28f34ef8959abaddf06edbc2ca1913824e9b2f171cc75
|
|
| MD5 |
f8a2fdc8135105067c45156ab3a02283
|
|
| BLAKE2b-256 |
68c9f55c237935a418dab196394a807ffe3a5dd849949c8aa269fdb94f0f83b2
|
Provenance
The following attestation bundles were made for pyxclip-0.2.3-cp313-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
publish.yml on abbazs/pyxclip
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyxclip-0.2.3-cp313-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
a3b38b03a41145d532d28f34ef8959abaddf06edbc2ca1913824e9b2f171cc75 - Sigstore transparency entry: 1155015093
- Sigstore integration time:
-
Permalink:
abbazs/pyxclip@4bdde3dbfdaa14d09cf9cd2f34584ca59acec64d -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/abbazs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4bdde3dbfdaa14d09cf9cd2f34584ca59acec64d -
Trigger Event:
push
-
Statement type:
File details
Details for the file pyxclip-0.2.3-cp313-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: pyxclip-0.2.3-cp313-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 382.8 kB
- Tags: CPython 3.13+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5532effc21de6999e543eae825398be9c99f8443d396dee58c1a7784e23e1b43
|
|
| MD5 |
0dac4dd8ae0df34221912265ca242fa9
|
|
| BLAKE2b-256 |
d8a627dfd81625606a5e3f5003b8b4ef22122358cd6a4111172a1df1da0d2224
|
Provenance
The following attestation bundles were made for pyxclip-0.2.3-cp313-abi3-macosx_11_0_arm64.whl:
Publisher:
publish.yml on abbazs/pyxclip
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyxclip-0.2.3-cp313-abi3-macosx_11_0_arm64.whl -
Subject digest:
5532effc21de6999e543eae825398be9c99f8443d396dee58c1a7784e23e1b43 - Sigstore transparency entry: 1155015083
- Sigstore integration time:
-
Permalink:
abbazs/pyxclip@4bdde3dbfdaa14d09cf9cd2f34584ca59acec64d -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/abbazs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4bdde3dbfdaa14d09cf9cd2f34584ca59acec64d -
Trigger Event:
push
-
Statement type:
File details
Details for the file pyxclip-0.2.3-cp313-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: pyxclip-0.2.3-cp313-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 402.0 kB
- Tags: CPython 3.13+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c859fa34d05ab463a9e5a872a8b3308a8f352824c1ff9815eb41f244e460d57e
|
|
| MD5 |
c9a8aefcabebec08a20f3a48428f58d0
|
|
| BLAKE2b-256 |
c69c652271f602703c810870ccf9d643a3d8879761291a84d2ec9ed3d76684c6
|
Provenance
The following attestation bundles were made for pyxclip-0.2.3-cp313-abi3-macosx_10_12_x86_64.whl:
Publisher:
publish.yml on abbazs/pyxclip
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyxclip-0.2.3-cp313-abi3-macosx_10_12_x86_64.whl -
Subject digest:
c859fa34d05ab463a9e5a872a8b3308a8f352824c1ff9815eb41f244e460d57e - Sigstore transparency entry: 1155015087
- Sigstore integration time:
-
Permalink:
abbazs/pyxclip@4bdde3dbfdaa14d09cf9cd2f34584ca59acec64d -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/abbazs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4bdde3dbfdaa14d09cf9cd2f34584ca59acec64d -
Trigger Event:
push
-
Statement type:
File details
Details for the file pyxclip-0.2.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: pyxclip-0.2.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 715.8 kB
- Tags: CPython 3.8+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
892d99a582496bd3bcf4fe1ccba8f8b4bfff86c4c642a9a220cb0b5e4c0ab862
|
|
| MD5 |
f1ff82f7815408892f555af803e6efe3
|
|
| BLAKE2b-256 |
51458fafd22234c3087151461c8cfd889a30c775fb6c266d01f17024ecc25c4b
|
Provenance
The following attestation bundles were made for pyxclip-0.2.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
publish.yml on abbazs/pyxclip
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyxclip-0.2.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
892d99a582496bd3bcf4fe1ccba8f8b4bfff86c4c642a9a220cb0b5e4c0ab862 - Sigstore transparency entry: 1155015095
- Sigstore integration time:
-
Permalink:
abbazs/pyxclip@4bdde3dbfdaa14d09cf9cd2f34584ca59acec64d -
Branch / Tag:
refs/tags/v0.2.3 - Owner: https://github.com/abbazs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@4bdde3dbfdaa14d09cf9cd2f34584ca59acec64d -
Trigger Event:
push
-
Statement type: