Python wrapper for exiftool to extract and manipulate metadata from image, video, and other media files
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
The ExifToolAlpha class provides experimental functionality for specialized use cases including enhanced error handling, batch operations, keyword management, and file-to-file tag copying. These features are considered alpha-quality and may change in future versions.
Wrapper methods with additional error handling, retry logic, and validation for robust batch processing.
class ExifToolAlpha(ExifToolHelper):
def execute_json_wrapper(self, filenames, params=None, retry_on_error=True):
"""
Execute JSON command with error handling and retry logic.
Parameters:
- filenames: iterable of str, files to process
- params: list or None, optional parameters
- retry_on_error: bool, retry on subprocess errors (default: True)
Returns:
list: list of metadata dictionaries
"""
def get_metadata_batch_wrapper(self, filenames, params=None):
"""
Get metadata for multiple files with additional checks.
Parameters:
- filenames: iterable, files to process
- params: list or None, optional parameters
Returns:
list: list of metadata dictionaries
"""
def get_metadata_wrapper(self, filename, params=None):
"""
Get metadata for single file with additional checks.
Parameters:
- filename: str, single file to process
- params: list or None, optional parameters
Returns:
dict: single metadata dictionary
"""Extended tag retrieval methods with additional validation and error handling.
def get_tags_batch_wrapper(self, tags, filenames, params=None):
"""
Get specific tags from multiple files with checks.
Parameters:
- tags: list, tag names to retrieve
- filenames: iterable, files to process
- params: list or None, optional parameters
Returns:
list: list of tag dictionaries
"""
def get_tags_wrapper(self, tags, filename, params=None):
"""
Get specific tags from single file.
Parameters:
- tags: list, tag names to retrieve
- filename: str, single file to process
- params: list or None, optional parameters
Returns:
dict: single tag dictionary
"""
def get_tag_batch_wrapper(self, tag, filenames, params=None):
"""
Get single tag value from multiple files.
Parameters:
- tag: str, single tag name
- filenames: iterable, files to process
- params: list or None, optional parameters
Returns:
list: list of tag values
"""
def get_tag_wrapper(self, tag, filename, params=None):
"""
Get single tag value from single file.
Parameters:
- tag: str, single tag name
- filename: str, single file to process
- params: list or None, optional parameters
Returns:
any: single tag value
"""Legacy methods for single tag extraction with existence checks.
def get_tag_batch(self, filenames, tag):
"""
Extract single tag from multiple files (legacy method).
Parameters:
- filenames: iterable, files to process
- tag: str, single tag name
Returns:
list or None: list of tag values or None
"""
def get_tag(self, filename, tag):
"""
Extract single tag from single file with existence checks.
Parameters:
- filename: str, file to process
- tag: str, tag name to retrieve
Returns:
any or None: tag value or None
Raises:
- FileNotFoundError: if file does not exist
- RuntimeError: if other processing errors occur
"""Advanced operations for copying tags between files and specialized metadata management.
def copy_tags(self, from_filename, to_filename):
"""
Copy all tags from one file to another.
Parameters:
- from_filename: str, source file
- to_filename: str, destination file
"""Specialized methods for managing IPTC Keywords tags with different operation modes.
def set_keywords_batch(self, files, mode, keywords):
"""
Modify keywords tag for multiple files.
Parameters:
- files: iterable, files to modify
- mode: int, operation mode (KW_REPLACE, KW_ADD, or KW_REMOVE)
- keywords: iterable of str, keywords to process
Returns:
str: command execution result
Raises:
- TypeError: if parameters have incorrect types
"""
def set_keywords(self, filename, mode, keywords):
"""
Modify keywords tag for single file.
Parameters:
- filename: str, file to modify
- mode: int, operation mode (KW_REPLACE, KW_ADD, or KW_REMOVE)
- keywords: iterable of str, keywords to process
Returns:
str: command execution result
"""Static methods for result validation and error checking.
@staticmethod
def _check_result_filelist(file_paths, result):
"""
Validate that result matches requested files.
Parameters:
- file_paths: list, requested file paths
- result: list, returned results from exiftool
Raises:
- IOError: if mismatch detected between requested and returned files
"""Keyword operation mode constants for use with keyword management methods.
KW_TAGNAME = "IPTC:Keywords" # Keywords tag name
KW_REPLACE = 0 # Replace keywords mode
KW_ADD = 1 # Add keywords mode
KW_REMOVE = 2 # Remove keywords modeHelper functions for result processing and error checking.
def strip_nl(s):
"""
Strip newlines from string, replacing with spaces.
Parameters:
- s: str, string to process
Returns:
str: string with newlines replaced by spaces
"""
def check_ok(result):
"""
Check if exiftool write operation succeeded.
Parameters:
- result: str, output from execute() method
Returns:
bool: True if operation appears successful
"""
def format_error(result):
"""
Format exiftool operation result as human-readable message.
Parameters:
- result: str, output from execute() method
Returns:
str: formatted status message
"""import exiftool
files = ['photo1.jpg', 'photo2.png', 'photo3.tiff']
with exiftool.ExifToolAlpha() as et:
# Enhanced error handling for batch operations
try:
metadata = et.get_metadata_batch_wrapper(files)
for data in metadata:
print(f"Processed: {data['SourceFile']}")
except Exception as e:
print(f"Batch processing failed: {e}")with exiftool.ExifToolAlpha() as et:
# Get single tag from multiple files
iso_values = et.get_tag_batch_wrapper('EXIF:ISO', files)
for i, iso in enumerate(iso_values):
print(f"{files[i]}: ISO {iso}")
# Get single tag with existence check
camera_make = et.get_tag('photo.jpg', 'EXIF:Make')
if camera_make:
print(f"Camera make: {camera_make}")
else:
print("No camera make information found")with exiftool.ExifToolAlpha() as et:
# Copy all metadata from source to destination
et.copy_tags('source_with_metadata.jpg', 'destination.jpg')
print("Tags copied successfully")from exiftool.experimental import KW_REPLACE, KW_ADD, KW_REMOVE
with exiftool.ExifToolAlpha() as et:
# Replace all keywords
et.set_keywords('photo.jpg', KW_REPLACE, ['landscape', 'nature', 'sunset'])
# Add new keywords
et.set_keywords('photo.jpg', KW_ADD, ['golden hour', 'mountains'])
# Remove specific keywords
et.set_keywords('photo.jpg', KW_REMOVE, ['sunset'])
# Batch keyword operations
et.set_keywords_batch(
files=['photo1.jpg', 'photo2.jpg'],
mode=KW_ADD,
keywords=['vacation', '2023']
)from exiftool.experimental import check_ok, format_error
with exiftool.ExifToolAlpha() as et:
# Execute operation and check result
result = et.execute('-overwrite_original', '-EXIF:Artist=Jane Doe', 'photo.jpg')
if check_ok(result):
print("Tags updated successfully")
else:
error_msg = format_error(result)
print(f"Operation failed: {error_msg}")with exiftool.ExifToolAlpha() as et:
requested_files = ['photo1.jpg', 'photo2.jpg', 'photo3.jpg']
# Get metadata with validation
metadata = et.get_metadata_batch_wrapper(requested_files)
# Validate results match request
try:
et._check_result_filelist(requested_files, metadata)
print("All files processed successfully")
except IOError as e:
print(f"File processing mismatch: {e}")Install with Tessl CLI
npx tessl i tessl/pypi-pyexiftool