0
# Exception Handling
1
2
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.
3
4
## Capabilities
5
6
### Base Exception Classes
7
8
Foundation exception classes that provide common interfaces and are never raised directly.
9
10
```python { .api }
11
class ExifToolException(Exception):
12
"""
13
Generic base class for all ExifTool error classes.
14
Use this for catch-all exception handling.
15
"""
16
17
class ExifToolProcessStateError(ExifToolException):
18
"""
19
Base class for all errors related to invalid state of exiftool subprocess.
20
Covers scenarios where subprocess is running when it shouldn't be or vice versa.
21
"""
22
23
class ExifToolExecuteException(ExifToolException):
24
"""
25
Base exception class for all execute() associated errors.
26
Never returned directly but provides common interface for subclassed errors.
27
28
Attributes:
29
- returncode: int, exit status from exiftool command
30
- cmd: list, parameters sent to exiftool that caused error
31
- stdout: str, STDOUT stream from failed command
32
- stderr: str, STDERR stream from failed command
33
"""
34
35
def __init__(self, message, exit_status, cmd_stdout, cmd_stderr, params):
36
"""
37
Initialize execute exception with detailed error context.
38
39
Parameters:
40
- message: str, error description
41
- exit_status: int, command exit status
42
- cmd_stdout: str, command stdout output
43
- cmd_stderr: str, command stderr output
44
- params: list, command parameters that failed
45
"""
46
```
47
48
### Process State Exceptions
49
50
Exceptions raised when subprocess operations are attempted in invalid states.
51
52
```python { .api }
53
class ExifToolRunning(ExifToolProcessStateError):
54
"""
55
Raised when trying to modify settings while subprocess is running.
56
Common scenarios: changing executable path, encoding, or common_args while running.
57
"""
58
59
def __init__(self, message: str):
60
"""
61
Initialize with descriptive message.
62
63
Parameters:
64
- message: str, description of what operation was attempted
65
"""
66
67
class ExifToolNotRunning(ExifToolProcessStateError):
68
"""
69
Raised when trying to execute commands while subprocess is not running.
70
Common scenarios: calling execute() before run() or after terminate().
71
"""
72
73
def __init__(self, message: str):
74
"""
75
Initialize with descriptive message.
76
77
Parameters:
78
- message: str, description of what operation was attempted
79
"""
80
```
81
82
### Execute Exceptions
83
84
Exceptions raised during command execution with detailed error information.
85
86
```python { .api }
87
class ExifToolExecuteError(ExifToolExecuteException):
88
"""
89
Raised when execute() returns non-zero exit status.
90
Most common execution error - indicates exiftool command failed.
91
"""
92
93
def __init__(self, exit_status, cmd_stdout, cmd_stderr, params):
94
"""
95
Initialize with command execution details.
96
97
Parameters:
98
- exit_status: int, non-zero exit status from exiftool
99
- cmd_stdout: str, stdout from failed command
100
- cmd_stderr: str, stderr from failed command
101
- params: list, command parameters that failed
102
"""
103
104
class ExifToolOutputEmptyError(ExifToolExecuteException):
105
"""
106
Raised when execute_json() expects output but execute() returns none.
107
Indicates mismatch between expected JSON output and actual command behavior.
108
"""
109
110
def __init__(self, exit_status, cmd_stdout, cmd_stderr, params):
111
"""
112
Initialize with empty output context.
113
114
Parameters:
115
- exit_status: int, command exit status
116
- cmd_stdout: str, empty stdout that was expected to contain JSON
117
- cmd_stderr: str, stderr output
118
- params: list, command parameters that produced no output
119
"""
120
121
class ExifToolJSONInvalidError(ExifToolExecuteException):
122
"""
123
Raised when execute_json() receives invalid JSON from exiftool.
124
Indicates JSON parsing failure of exiftool output.
125
"""
126
127
def __init__(self, exit_status, cmd_stdout, cmd_stderr, params):
128
"""
129
Initialize with invalid JSON context.
130
131
Parameters:
132
- exit_status: int, command exit status
133
- cmd_stdout: str, stdout containing invalid JSON
134
- cmd_stderr: str, stderr output
135
- params: list, command parameters that produced invalid JSON
136
"""
137
```
138
139
### Other Exceptions
140
141
Specialized exceptions for specific error conditions.
142
143
```python { .api }
144
class ExifToolVersionError(ExifToolException):
145
"""
146
Raised when exiftool version requirements are not met.
147
PyExifTool requires exiftool version 12.15 or later for full functionality.
148
"""
149
150
class ExifToolTagNameError(ExifToolException):
151
"""
152
Raised when invalid tag names are detected by ExifToolHelper.
153
Only occurs when check_tag_names is enabled and invalid tag format is found.
154
"""
155
156
def __init__(self, bad_tag):
157
"""
158
Initialize with invalid tag name.
159
160
Parameters:
161
- bad_tag: str, the invalid tag name that was detected
162
"""
163
```
164
165
## Usage Examples
166
167
### Basic Exception Handling
168
169
```python
170
import exiftool
171
from exiftool.exceptions import ExifToolException, ExifToolExecuteError
172
173
try:
174
with exiftool.ExifToolHelper() as et:
175
metadata = et.get_metadata('nonexistent.jpg')
176
except ExifToolExecuteError as e:
177
print(f"Command failed with exit status {e.returncode}")
178
print(f"Error output: {e.stderr}")
179
print(f"Command: {' '.join(e.cmd)}")
180
except ExifToolException as e:
181
print(f"ExifTool error: {e}")
182
except Exception as e:
183
print(f"Unexpected error: {e}")
184
```
185
186
### Specific Exception Handling
187
188
```python
189
from exiftool.exceptions import (
190
ExifToolNotRunning,
191
ExifToolRunning,
192
ExifToolJSONInvalidError,
193
ExifToolTagNameError
194
)
195
196
et = exiftool.ExifTool()
197
198
try:
199
# This will raise ExifToolNotRunning
200
et.execute('-ver')
201
except ExifToolNotRunning as e:
202
print(f"Need to start subprocess first: {e}")
203
et.run()
204
205
try:
206
# This might raise ExifToolJSONInvalidError
207
result = et.execute_json('-invalid-json-command')
208
except ExifToolJSONInvalidError as e:
209
print(f"JSON parsing failed: {e}")
210
print(f"Raw output was: {e.stdout}")
211
212
try:
213
# This will raise ExifToolRunning
214
et.executable = '/different/path/exiftool'
215
except ExifToolRunning as e:
216
print(f"Cannot change settings while running: {e}")
217
218
et.terminate()
219
```
220
221
### Helper Class Exception Handling
222
223
```python
224
from exiftool.exceptions import ExifToolTagNameError
225
226
with exiftool.ExifToolHelper(check_tag_names=True) as et:
227
try:
228
# This will raise ExifToolTagNameError if tag format is invalid
229
et.get_tags('photo.jpg', ['Invalid:Tag:Format'])
230
except ExifToolTagNameError as e:
231
print(f"Invalid tag name: {e}")
232
233
try:
234
# Disable tag checking for this operation
235
et.check_tag_names = False
236
et.get_tags('photo.jpg', ['Invalid:Tag:Format']) # Won't raise error
237
except ExifToolExecuteError as e:
238
print(f"Command failed at exiftool level: {e}")
239
```
240
241
### Comprehensive Error Handling Pattern
242
243
```python
244
import exiftool
245
from exiftool.exceptions import (
246
ExifToolException,
247
ExifToolProcessStateError,
248
ExifToolExecuteException,
249
ExifToolExecuteError,
250
ExifToolVersionError
251
)
252
253
def safe_get_metadata(file_paths):
254
"""
255
Safely extract metadata with comprehensive error handling.
256
"""
257
try:
258
with exiftool.ExifToolHelper() as et:
259
return et.get_metadata(file_paths)
260
261
except ExifToolVersionError as e:
262
print(f"ExifTool version incompatible: {e}")
263
print("Please update to exiftool 12.15 or later")
264
return None
265
266
except ExifToolExecuteError as e:
267
print(f"Command execution failed:")
268
print(f" Exit status: {e.returncode}")
269
print(f" Command: {' '.join(e.cmd)}")
270
if e.stderr:
271
print(f" Error: {e.stderr}")
272
return None
273
274
except ExifToolProcessStateError as e:
275
print(f"Subprocess state error: {e}")
276
return None
277
278
except ExifToolException as e:
279
print(f"ExifTool library error: {e}")
280
return None
281
282
except Exception as e:
283
print(f"Unexpected error: {e}")
284
return None
285
286
# Usage
287
metadata = safe_get_metadata(['photo1.jpg', 'photo2.png'])
288
if metadata:
289
for data in metadata:
290
print(f"Successfully processed: {data['SourceFile']}")
291
```
292
293
### Error Information Extraction
294
295
```python
296
from exiftool.exceptions import ExifToolExecuteException
297
298
try:
299
with exiftool.ExifTool() as et:
300
et.execute('-invalid-option', 'file.jpg')
301
except ExifToolExecuteException as e:
302
# Access detailed error information
303
print(f"Command that failed: {' '.join(e.cmd)}")
304
print(f"Exit code: {e.returncode}")
305
print(f"Standard output: {e.stdout}")
306
print(f"Error output: {e.stderr}")
307
308
# Error information can be used for logging or debugging
309
error_details = {
310
'command': e.cmd,
311
'exit_code': e.returncode,
312
'stdout': e.stdout,
313
'stderr': e.stderr,
314
'error_type': type(e).__name__
315
}
316
print(f"Error details: {error_details}")
317
```