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
PyExifTool provides a comprehensive exception hierarchy for different error conditions with detailed error information including exit codes, command output, and specific error contexts. All exceptions inherit from the base ExifToolException class for easy catch-all error handling.
Foundation exception classes that provide common interfaces and are never raised directly.
class ExifToolException(Exception):
"""
Generic base class for all ExifTool error classes.
Use this for catch-all exception handling.
"""
class ExifToolProcessStateError(ExifToolException):
"""
Base class for all errors related to invalid state of exiftool subprocess.
Covers scenarios where subprocess is running when it shouldn't be or vice versa.
"""
class ExifToolExecuteException(ExifToolException):
"""
Base exception class for all execute() associated errors.
Never returned directly but provides common interface for subclassed errors.
Attributes:
- returncode: int, exit status from exiftool command
- cmd: list, parameters sent to exiftool that caused error
- stdout: str, STDOUT stream from failed command
- stderr: str, STDERR stream from failed command
"""
def __init__(self, message, exit_status, cmd_stdout, cmd_stderr, params):
"""
Initialize execute exception with detailed error context.
Parameters:
- message: str, error description
- exit_status: int, command exit status
- cmd_stdout: str, command stdout output
- cmd_stderr: str, command stderr output
- params: list, command parameters that failed
"""Exceptions raised when subprocess operations are attempted in invalid states.
class ExifToolRunning(ExifToolProcessStateError):
"""
Raised when trying to modify settings while subprocess is running.
Common scenarios: changing executable path, encoding, or common_args while running.
"""
def __init__(self, message: str):
"""
Initialize with descriptive message.
Parameters:
- message: str, description of what operation was attempted
"""
class ExifToolNotRunning(ExifToolProcessStateError):
"""
Raised when trying to execute commands while subprocess is not running.
Common scenarios: calling execute() before run() or after terminate().
"""
def __init__(self, message: str):
"""
Initialize with descriptive message.
Parameters:
- message: str, description of what operation was attempted
"""Exceptions raised during command execution with detailed error information.
class ExifToolExecuteError(ExifToolExecuteException):
"""
Raised when execute() returns non-zero exit status.
Most common execution error - indicates exiftool command failed.
"""
def __init__(self, exit_status, cmd_stdout, cmd_stderr, params):
"""
Initialize with command execution details.
Parameters:
- exit_status: int, non-zero exit status from exiftool
- cmd_stdout: str, stdout from failed command
- cmd_stderr: str, stderr from failed command
- params: list, command parameters that failed
"""
class ExifToolOutputEmptyError(ExifToolExecuteException):
"""
Raised when execute_json() expects output but execute() returns none.
Indicates mismatch between expected JSON output and actual command behavior.
"""
def __init__(self, exit_status, cmd_stdout, cmd_stderr, params):
"""
Initialize with empty output context.
Parameters:
- exit_status: int, command exit status
- cmd_stdout: str, empty stdout that was expected to contain JSON
- cmd_stderr: str, stderr output
- params: list, command parameters that produced no output
"""
class ExifToolJSONInvalidError(ExifToolExecuteException):
"""
Raised when execute_json() receives invalid JSON from exiftool.
Indicates JSON parsing failure of exiftool output.
"""
def __init__(self, exit_status, cmd_stdout, cmd_stderr, params):
"""
Initialize with invalid JSON context.
Parameters:
- exit_status: int, command exit status
- cmd_stdout: str, stdout containing invalid JSON
- cmd_stderr: str, stderr output
- params: list, command parameters that produced invalid JSON
"""Specialized exceptions for specific error conditions.
class ExifToolVersionError(ExifToolException):
"""
Raised when exiftool version requirements are not met.
PyExifTool requires exiftool version 12.15 or later for full functionality.
"""
class ExifToolTagNameError(ExifToolException):
"""
Raised when invalid tag names are detected by ExifToolHelper.
Only occurs when check_tag_names is enabled and invalid tag format is found.
"""
def __init__(self, bad_tag):
"""
Initialize with invalid tag name.
Parameters:
- bad_tag: str, the invalid tag name that was detected
"""import exiftool
from exiftool.exceptions import ExifToolException, ExifToolExecuteError
try:
with exiftool.ExifToolHelper() as et:
metadata = et.get_metadata('nonexistent.jpg')
except ExifToolExecuteError as e:
print(f"Command failed with exit status {e.returncode}")
print(f"Error output: {e.stderr}")
print(f"Command: {' '.join(e.cmd)}")
except ExifToolException as e:
print(f"ExifTool error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")from exiftool.exceptions import (
ExifToolNotRunning,
ExifToolRunning,
ExifToolJSONInvalidError,
ExifToolTagNameError
)
et = exiftool.ExifTool()
try:
# This will raise ExifToolNotRunning
et.execute('-ver')
except ExifToolNotRunning as e:
print(f"Need to start subprocess first: {e}")
et.run()
try:
# This might raise ExifToolJSONInvalidError
result = et.execute_json('-invalid-json-command')
except ExifToolJSONInvalidError as e:
print(f"JSON parsing failed: {e}")
print(f"Raw output was: {e.stdout}")
try:
# This will raise ExifToolRunning
et.executable = '/different/path/exiftool'
except ExifToolRunning as e:
print(f"Cannot change settings while running: {e}")
et.terminate()from exiftool.exceptions import ExifToolTagNameError
with exiftool.ExifToolHelper(check_tag_names=True) as et:
try:
# This will raise ExifToolTagNameError if tag format is invalid
et.get_tags('photo.jpg', ['Invalid:Tag:Format'])
except ExifToolTagNameError as e:
print(f"Invalid tag name: {e}")
try:
# Disable tag checking for this operation
et.check_tag_names = False
et.get_tags('photo.jpg', ['Invalid:Tag:Format']) # Won't raise error
except ExifToolExecuteError as e:
print(f"Command failed at exiftool level: {e}")import exiftool
from exiftool.exceptions import (
ExifToolException,
ExifToolProcessStateError,
ExifToolExecuteException,
ExifToolExecuteError,
ExifToolVersionError
)
def safe_get_metadata(file_paths):
"""
Safely extract metadata with comprehensive error handling.
"""
try:
with exiftool.ExifToolHelper() as et:
return et.get_metadata(file_paths)
except ExifToolVersionError as e:
print(f"ExifTool version incompatible: {e}")
print("Please update to exiftool 12.15 or later")
return None
except ExifToolExecuteError as e:
print(f"Command execution failed:")
print(f" Exit status: {e.returncode}")
print(f" Command: {' '.join(e.cmd)}")
if e.stderr:
print(f" Error: {e.stderr}")
return None
except ExifToolProcessStateError as e:
print(f"Subprocess state error: {e}")
return None
except ExifToolException as e:
print(f"ExifTool library error: {e}")
return None
except Exception as e:
print(f"Unexpected error: {e}")
return None
# Usage
metadata = safe_get_metadata(['photo1.jpg', 'photo2.png'])
if metadata:
for data in metadata:
print(f"Successfully processed: {data['SourceFile']}")from exiftool.exceptions import ExifToolExecuteException
try:
with exiftool.ExifTool() as et:
et.execute('-invalid-option', 'file.jpg')
except ExifToolExecuteException as e:
# Access detailed error information
print(f"Command that failed: {' '.join(e.cmd)}")
print(f"Exit code: {e.returncode}")
print(f"Standard output: {e.stdout}")
print(f"Error output: {e.stderr}")
# Error information can be used for logging or debugging
error_details = {
'command': e.cmd,
'exit_code': e.returncode,
'stdout': e.stdout,
'stderr': e.stderr,
'error_type': type(e).__name__
}
print(f"Error details: {error_details}")Install with Tessl CLI
npx tessl i tessl/pypi-pyexiftool