Smartcard library for Python providing PC/SC interface for smart card communication
—
Functions for discovering and managing smart card readers, including reader groups and system-level reader operations. This module provides the foundation for all smart card reader interactions.
Core functions for listing and managing smart card readers at the system level.
def readers(groups=None):
"""
Get list of smart card readers as Reader objects.
Args:
groups (list[str], optional): Reader groups to search. If None, searches all groups.
Returns:
list[Reader]: List of available readers
Example groups: ['SCard$DefaultReaders', 'MyReaderGroup']
"""
def readergroups():
"""
Get list of all reader groups in the system.
Returns:
list[str]: List of reader group names
"""The Reader class represents individual smart card readers and provides methods for connection management.
class Reader:
def __init__(self, readername):
"""
Create a reader object.
Args:
readername (str): Name of the smart card reader
"""
def createConnection(self):
"""
Create a connection to this reader for card communication.
Returns:
CardConnection: New connection object for this reader
Raises:
ReaderException: If connection creation fails
"""
def addtoreadergroup(self, groupname):
"""
Add this reader to a reader group.
Args:
groupname (str): Name of the reader group
"""
def removefromreadergroup(self, groupname):
"""
Remove this reader from a reader group.
Args:
groupname (str): Name of the reader group
"""
def __eq__(self, other):
"""
Check reader equality based on name.
Args:
other (Reader): Other reader to compare
Returns:
bool: True if readers have the same name
"""
def __hash__(self):
"""
Get hash value based on reader name.
Returns:
int: Hash value for use in sets and dictionaries
"""
def __repr__(self):
"""
Get detailed string representation.
Returns:
str: Detailed reader representation
"""
def __str__(self):
"""
Get reader name string.
Returns:
str: Reader name
"""Factory functions for creating and managing reader instances.
def createReader(clazz, readername):
"""
Create a reader instance from a class name.
Args:
clazz (str): Reader class name
readername (str): Name of the reader
Returns:
Reader: New reader instance
"""from smartcard.System import readers, readergroups
# List all available readers
reader_list = readers()
print(f"Found {len(reader_list)} readers:")
for i, reader in enumerate(reader_list):
print(f" {i}: {reader}")
# List reader groups
groups = readergroups()
print(f"\nReader groups: {groups}")
# Get readers from specific groups
if groups:
group_readers = readers([groups[0]])
print(f"\nReaders in '{groups[0]}': {len(group_readers)}")from smartcard.System import readers
reader_list = readers()
if reader_list:
reader = reader_list[0]
print(f"Reader name: {reader}")
print(f"Reader repr: {repr(reader)}")
print(f"Reader type: {type(reader)}")
# Reader comparison
same_reader = readers()[0]
print(f"Same reader: {reader == same_reader}") # True
# Use reader in a set (requires __hash__)
reader_set = {reader}
print(f"Reader in set: {reader in reader_set}") # Truefrom smartcard.System import readers
from smartcard.Exceptions import CardConnectionException
def test_reader_connection(reader):
"""Test connection capabilities of a reader."""
try:
print(f"Testing reader: {reader}")
# Create connection
connection = reader.createConnection()
print("✓ Connection created successfully")
# Test connection properties
print(f"Connection type: {type(connection)}")
print(f"Reader from connection: {connection.getReader()}")
# Try to connect (may fail if no card present)
try:
connection.connect()
print("✓ Connected to card")
# Get card information
atr = connection.getATR()
protocol = connection.getProtocol()
print(f"ATR: {' '.join(f'{b:02X}' for b in atr)}")
print(f"Protocol: {protocol}")
connection.disconnect()
print("✓ Disconnected successfully")
except CardConnectionException as e:
print(f"ⓘ No card present or connection failed: {e}")
except Exception as e:
print(f"✗ Reader test failed: {e}")
print()
# Test all readers
reader_list = readers()
for reader in reader_list:
test_reader_connection(reader)from smartcard.System import readers, readergroups
def manage_reader_groups():
"""Demonstrate reader group management."""
reader_list = readers()
if not reader_list:
print("No readers available")
return
reader = reader_list[0]
print(f"Working with reader: {reader}")
# Show current groups
current_groups = readergroups()
print(f"Current groups: {current_groups}")
# Add reader to a custom group (may require admin privileges)
custom_group = "MyApplicationGroup"
try:
reader.addtoreadergroup(custom_group)
print(f"✓ Added reader to '{custom_group}'")
# Check if group was created
updated_groups = readergroups()
if custom_group in updated_groups:
print(f"✓ Group '{custom_group}' is now available")
# Remove reader from group
reader.removefromreadergroup(custom_group)
print(f"✓ Removed reader from '{custom_group}'")
except Exception as e:
print(f"ⓘ Group management failed (may require admin privileges): {e}")
manage_reader_groups()import time
from smartcard.System import readers
def monitor_reader_changes(duration=30):
"""Monitor for reader connection/disconnection events."""
print(f"Monitoring readers for {duration} seconds...")
print("Connect or disconnect readers to see changes")
last_readers = set(str(r) for r in readers())
print(f"Initial readers: {len(last_readers)}")
for reader in last_readers:
print(f" {reader}")
print()
start_time = time.time()
while time.time() - start_time < duration:
current_readers = set(str(r) for r in readers())
# Check for changes
added = current_readers - last_readers
removed = last_readers - current_readers
if added:
print(f"✓ Readers connected: {added}")
if removed:
print(f"✗ Readers disconnected: {removed}")
if added or removed:
print(f"Current reader count: {len(current_readers)}")
last_readers = current_readers
print()
time.sleep(1)
print("Monitoring completed")
# Run monitoring
monitor_reader_changes(10)import platform
from smartcard.System import readers
def analyze_system_readers():
"""Analyze readers based on operating system."""
system = platform.system()
reader_list = readers()
print(f"Operating System: {system}")
print(f"Total readers: {len(reader_list)}")
print()
for i, reader in enumerate(reader_list):
reader_name = str(reader)
print(f"Reader {i+1}: {reader_name}")
# Identify reader types based on naming patterns
if system == "Windows":
if "CCID" in reader_name:
print(" Type: CCID (Generic)")
elif "PICC" in reader_name:
print(" Type: Contactless")
elif "Microsoft" in reader_name:
print(" Type: Windows built-in")
elif system == "Darwin": # macOS
if "CCID" in reader_name:
print(" Type: CCID")
elif "PICC" in reader_name:
print(" Type: Contactless")
elif system == "Linux":
if "CCID" in reader_name:
print(" Type: CCID")
elif "pc/sc" in reader_name.lower():
print(" Type: PC/SC")
# Test connection capability
try:
connection = reader.createConnection()
print(" Status: Connection OK")
except Exception as e:
print(f" Status: Connection failed - {e}")
print()
analyze_system_readers()# Type aliases
ReaderName = str
ReaderGroupName = str
ReaderList = list[Reader]
# Exception types for reader operations
class ReaderException(SmartcardException):
"""Base exception for reader operations."""
class ListReadersException(SmartcardException):
"""Raised when reader listing fails."""
class InvalidReaderException(SmartcardException):
"""Raised when specified reader is invalid."""Install with Tessl CLI
npx tessl i tessl/pypi-pyscard