Summary
A thorough code audit of zm_detect.py, hook helpers, and pyzm revealed multiple bugs where config options are silently ignored, a lock deadlock, dead legacy code from the ini→yml migration, and local/remote behavioral differences.
HIGH Severity
- H1:
ModelConfig.options never populated from YAML — config.py:_seq_item_to_model_config() never sets the options dict. ALL ALPR extended options (platerec_regions, openalpr_country, openalpr_cmdline_binary, etc.) and face unknown_face_name are silently ignored.
- H4:
face_dlib.py lock deadlock — Lock acquired at line 131, released at 152, with no try/finally. If face_recognition raises, the portalocker semaphore is never released → permanent deadlock.
- H6:
exit(0) on config error — utils.py:364 exits with code 0 on config parse failure, signaling success to zmeventnotification.pl.
- H7:
image_manip.py SSL not honored — requests.get() and imageio.imread() never pass verify=False for self-signed certs.
- H8: YAML boolean handling —
enabled: false, match_past_detections: true, save_unknown_faces: true all broken because code compares against string "yes"/"no" but YAML parses booleans as Python bool.
- H9:
max_lock_wait/max_processes not read from YAML — _seq_item_to_model_config() never extracts these; users always get defaults.
MEDIUM Severity
- H10:
ignore_pattern short-circuits zone matching — break in filters.py:93 prevents checking other zones.
- H11:
detect_urls missing original_shape — Server route doesn't pass original_shape, causing wrong zone filtering with resized images.
- M1:
face_dlib.py downscaling dead — max_size = Width then if Width > max_size → always false.
- M2:
ZeroDivisionError in animation — fps=round(totframes/total_time) crashes when total_time rounds to 0.
- M7:
FIRST_NEW not handled in server — serve/app.py only checks FIRST, not FIRST_NEW.
- M11:
zm.event() called 3 times — Same API call repeated for write_image, notes, and tagging.
- M15:
ServerConfig.detector_config ignored — Field exists but create_app() never uses it.
Dead Code Cleanup
apigw.py + log.py — entire files unused by production code
common_params.py — ~12 config keys defined but never read
utils.py — dead imports (logging, datetime, time), dead functions (str2arr, rescale_polygons)
image_manip.py — dead imports (Polygon, cv2, numpy, pickle, re)
face_dlib.py — duplicate time import, dead downscaling block
filters.py — filter_past_detections() wrapper never called from production
serve/app.py — zone-parsing duplicated across two routes
DRY
- Zone-parsing logic duplicated in
/detect and /detect_urls server routes
zm.event() fetched 3 times for the same event ID
Summary
A thorough code audit of
zm_detect.py, hook helpers, andpyzmrevealed multiple bugs where config options are silently ignored, a lock deadlock, dead legacy code from the ini→yml migration, and local/remote behavioral differences.HIGH Severity
ModelConfig.optionsnever populated from YAML —config.py:_seq_item_to_model_config()never sets theoptionsdict. ALL ALPR extended options (platerec_regions,openalpr_country,openalpr_cmdline_binary, etc.) and faceunknown_face_nameare silently ignored.face_dlib.pylock deadlock — Lock acquired at line 131, released at 152, with notry/finally. Ifface_recognitionraises, the portalocker semaphore is never released → permanent deadlock.exit(0)on config error —utils.py:364exits with code 0 on config parse failure, signaling success tozmeventnotification.pl.image_manip.pySSL not honored —requests.get()andimageio.imread()never passverify=Falsefor self-signed certs.enabled: false,match_past_detections: true,save_unknown_faces: trueall broken because code compares against string"yes"/"no"but YAML parses booleans as Pythonbool.max_lock_wait/max_processesnot read from YAML —_seq_item_to_model_config()never extracts these; users always get defaults.MEDIUM Severity
ignore_patternshort-circuits zone matching —breakinfilters.py:93prevents checking other zones.detect_urlsmissingoriginal_shape— Server route doesn't passoriginal_shape, causing wrong zone filtering with resized images.face_dlib.pydownscaling dead —max_size = Widththenif Width > max_size→ always false.ZeroDivisionErrorin animation —fps=round(totframes/total_time)crashes whentotal_timerounds to 0.FIRST_NEWnot handled in server —serve/app.pyonly checksFIRST, notFIRST_NEW.zm.event()called 3 times — Same API call repeated for write_image, notes, and tagging.ServerConfig.detector_configignored — Field exists butcreate_app()never uses it.Dead Code Cleanup
apigw.py+log.py— entire files unused by production codecommon_params.py— ~12 config keys defined but never readutils.py— dead imports (logging,datetime,time), dead functions (str2arr,rescale_polygons)image_manip.py— dead imports (Polygon,cv2,numpy,pickle,re)face_dlib.py— duplicatetimeimport, dead downscaling blockfilters.py—filter_past_detections()wrapper never called from productionserve/app.py— zone-parsing duplicated across two routesDRY
/detectand/detect_urlsserver routeszm.event()fetched 3 times for the same event ID