TEM3: Exception handling & change timeout period¶
This tutorial explains the exception mechanism of PyJEM TEM3.
When a TEM API call fails, a TEMError exception is raised.
TEMError contains two pieces of information decoded from the error code returned by the equipment:
Attribute |
Type |
Description |
|---|---|---|
|
|
Raw error code returned from the equipment |
|
|
Category of the error (e.g. timeout, argument error) |
|
|
Human-readable description of the error |
The error message format is:
[<ErrorTypeKind>] <ErrorCodeKind description>
For example: [EOS] Timeout error.
Exception class structure¶
TEMError (Exception)
├─ code : int — raw error code
├─ kind : ErrorCodeKind — error category
└─ label : str — description
ErrorTypeKind (Enum) — subsystem that raised the error
ErrorCodeKind (Enum) — type of error
1. Import¶
1from PyJEM import TEM3
2from PyJEM.TEM3.exception import TEMError, ErrorTypeKind, ErrorCodeKind
2. ErrorTypeKind — subsystem that raised the error¶
ErrorTypeKind identifies which TEM subsystem raised the error.
It is decoded from the upper bits of the raw error code.
1print("ErrorTypeKind members:")
2for member in ErrorTypeKind:
3 print(f" {member.name:12} = {member.value}")
ErrorTypeKind members:
TEM = 1
EOS = 2
Lens = 3
Def = 4
Screen = 5
Camera = 6
Gonio = 7
PASYS = 10
HT = 16
GUN = 17
FEG = 18
Filter = 19
Stage = 20
Detector = 21
Apt = 22
Scan = 23
MDS = 24
VACUUM = 25
NITROGEN = 26
Notify = 30
general = 31
3. ErrorCodeKind — category of the error¶
ErrorCodeKind identifies what kind of error occurred.
It is decoded from the lower bits of the raw error code.
1print("ErrorCodeKind members:")
2for member in ErrorCodeKind:
3 print(f" {member.name:10} = {member.value:3} — {member.label}")
ErrorCodeKind members:
ARG = 1 — Argment error.
BUSY = 3 — Socket busy.
TIMEOUT = 10 — Timeout error.
ALLOC = 11 — Memory allocation error.
SOCKET = 12 — There is no socket connected or was cut off
TEMERR = 13 — An error was returned from the equipment.
NETDATA = 14 — Data packet error.
GUNTYPE = 16 — GUN type error. This module cannot be used with gun.
I_ARG = 100 — Internal parameter error
4. Triggering a real TEMError with EOS3.UpSelector()¶
EOS3.UpSelector() increments the magnification selector and waits for the ChgMag event (timeout: 3 seconds).
When the TEM is not in a state where the selector can be changed (e.g. already at maximum, or not connected), a TEMError is raised.
The try / except TEMError block below catches the error and inspects its attributes.
Note
This requires a live TEM3 connection.
If TEM3 is not connected, a TEMError with ErrorCodeKind.SOCKET or ErrorCodeKind.TIMEOUT is expected.
1eos = TEM3.EOS3()
2
3try:
4 eos.UpSelector()
5 print("UpSelector succeeded.")
6except TEMError as e:
7 print("TEMError caught!")
8 print(f" message : {e}")
9 print(f" code : {e.code}")
10 print(f" kind : {e.kind}")
11 print(f" label : {e.label}")
TEMError caught!
message : [EOS] An error was returned from the equipment.
code : 2061
kind : ErrorCodeKind.TEMERR
label : An error was returned from the equipment.
2026-04-03 17:59:00,584 INFO execute: UpSelector, args=None
2026-04-03 17:59:00,643 INFO return check: <class 'int'>, expected=None
5. Branching on error kind¶
You can branch on e.kind to handle specific error categories differently.
except TEMError as e:
if e.kind == ErrorCodeKind.TIMEOUT:
# retry or notify timeout
elif e.kind == ErrorCodeKind.SOCKET:
# reconnect
else:
raise # re-raise unexpected errors
1try:
2 eos.UpSelector()
3 print("UpSelector succeeded.")
4except TEMError as e:
5 if e.kind == ErrorCodeKind.TIMEOUT:
6 print("Timeout: the equipment did not respond in time.")
7 elif e.kind == ErrorCodeKind.SOCKET:
8 print("Socket error: TEM3 is not connected.")
9 elif e.kind == ErrorCodeKind.TEMERR:
10 print("Equipment error: the TEM returned an error.")
11 else:
12 print(f"Unhandled TEMError — kind={e.kind.name}, label={e.label}")
13 raise
Equipment error: the TEM returned an error.
2026-04-03 17:59:25,399 INFO execute: UpSelector, args=None
2026-04-03 17:59:25,458 INFO return check: <class 'int'>, expected=None
6. Extending the timeout with TEM3.SetRecvTimeout()¶
When a TEMError with ErrorCodeKind.TIMEOUT is raised, it means the TEM equipment did not respond within the communication timeout period.
You can extend the timeout by calling TEM3.SetRecvTimeout() before retrying the operation.
TEM3.SetRecvTimeout(value) # value: timeout in milliseconds (ms)
The default timeout is typically 3000 ms (3 seconds).
Increase the value if the equipment requires more time to complete the operation.
Note
SetRecvTimeout affects all subsequent TEM3 API calls in the session.
Restore the original value after the operation if needed.
1DEFAULT_TIMEOUT_MS = 3000 # default timeout
2EXTENDED_TIMEOUT_MS = 10000 # 10 seconds
3
4try:
5 eos.UpSelector()
6 print("UpSelector succeeded.")
7except TEMError as e:
8 if e.kind == ErrorCodeKind.TIMEOUT:
9 print(f"Timeout occurred. Extending timeout to {EXTENDED_TIMEOUT_MS} ms and retrying...")
10 TEM3.SetRecvTimeout(EXTENDED_TIMEOUT_MS)