fix: make script help paths lightweight (#1937)

## Summary

Consolidate the script help/startup fixes so standalone helper commands
can show usage without requiring runtime-only dependencies or generating
files.

## Details

Several helper scripts imported optional packages, evaluated newer
annotations, or started generation before users could inspect CLI usage.
On a fresh checkout, this made common help paths fail on missing
packages such as `cairosvg`, `Pillow`, `freetype-py`, `fontTools`,
`pyphen`, `pyserial`, or on Python 3.9 annotation evaluation. A few
generators also treated `--help` as a normal output argument and wrote
files instead of printing usage.

This change keeps runtime dependencies on the code paths that need them,
handles lightweight help/list commands first, and adds explicit `--help`
handling for generator scripts that previously started work.

## Validation

- `python3 <script> --help` across tracked Python scripts, excluding
`scripts/patch_jpegdec.py` because it is a PlatformIO pre-build hook
rather than a standalone CLI
- `python3 scripts/convert_icon.py` still exits with usage for missing
required arguments
- `python3 lib/EpdFont/scripts/fontconvert_sdcard.py --list-presets`
- `python3 -m py_compile` for the changed scripts
This commit is contained in:
Danila Yudin
2026-05-11 11:21:13 -05:00
committed by GitHub
parent accd50b593
commit 63e92ec74e
10 changed files with 81 additions and 40 deletions
+12 -6
View File
@@ -1,18 +1,21 @@
import sys
import os
from PIL import Image
import cairosvg
import io
import sys
threshold = 128
USAGE = 'Usage: python scripts/convert_icon.py input.png|input.svg output_name width height'
def svg_to_png_bytes(svg_path, width, height):
import cairosvg
with open(svg_path, 'rb') as f:
svg_data = f.read()
png_bytes = cairosvg.svg2png(bytestring=svg_data, output_width=width, output_height=height)
return png_bytes
def load_image(path, width, height):
from PIL import Image
ext = os.path.splitext(path)[1].lower()
if ext == '.svg':
png_bytes = svg_to_png_bytes(path, width, height)
@@ -58,8 +61,11 @@ def image_to_c_array(img, array_name):
return c
def main():
if len(sys.argv) < 5:
print('Usage: python convert_image.py input.png output_name width height')
if any(arg in ('-h', '--help') for arg in sys.argv[1:]):
print(USAGE)
sys.exit(0)
if len(sys.argv) != 5:
print(USAGE)
sys.exit(1)
input_path, output_name, width, height = sys.argv[1:5]
array_name = output_name.capitalize() + 'Icon'
@@ -77,4 +83,4 @@ def main():
print(f'Wrote {output_path}')
if __name__ == '__main__':
main()
main()
+38 -28
View File
@@ -35,6 +35,43 @@ import threading
from collections import deque
from datetime import datetime
DEFAULT_BAUDRATE = 115200
def build_arg_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
description="ESP32 Serial Monitor with Memory Graph - Real-time monitoring, graphing, and command interface"
)
parser.add_argument(
"port",
nargs="?",
default=None,
help="Serial port (leave empty for autodetection)",
)
parser.add_argument(
"--baud",
type=int,
default=DEFAULT_BAUDRATE,
help=f"Baud rate (default: {DEFAULT_BAUDRATE})",
)
parser.add_argument(
"--filter",
type=str,
default="",
help="Only display lines containing this keyword (case-insensitive)",
)
parser.add_argument(
"--suppress",
type=str,
default="",
help="Suppress lines containing this keyword (case-insensitive)",
)
return parser
if any(arg in ("-h", "--help") for arg in sys.argv[1:]):
build_arg_parser().parse_args()
# Try to import potentially missing packages
PACKAGE_MAPPING: dict[str, str] = {
"serial": "pyserial",
@@ -401,34 +438,7 @@ def main() -> None:
- Screenshot capture capability
- Graceful shutdown on Ctrl-C or window close
"""
parser = argparse.ArgumentParser(
description="ESP32 Serial Monitor with Memory Graph - Real-time monitoring, graphing, and command interface"
)
default_baudrate = 115200
parser.add_argument(
"port",
nargs="?",
default=None,
help="Serial port (leave empty for autodetection)",
)
parser.add_argument(
"--baud",
type=int,
default=default_baudrate,
help=f"Baud rate (default: {default_baudrate})",
)
parser.add_argument(
"--filter",
type=str,
default="",
help="Only display lines containing this keyword (case-insensitive)",
)
parser.add_argument(
"--suppress",
type=str,
default="",
help="Suppress lines containing this keyword (case-insensitive)",
)
parser = build_arg_parser()
args = parser.parse_args()
port = args.port
if port is None:
+2
View File
@@ -16,6 +16,8 @@ The input directory may be flat (all .cpfont files in one dir) or nested
convention <FamilyName>_<size>.cpfont.
"""
from __future__ import annotations
import argparse
import json
import os
@@ -137,10 +137,15 @@ Also includes:
import io
import os
import sys
import zipfile
import uuid
from datetime import datetime
if any(arg in ("-h", "--help") for arg in sys.argv[1:]):
print(__doc__.strip())
sys.exit(0)
try:
from PIL import Image, ImageDraw, ImageFont
except ImportError:
+3
View File
@@ -326,4 +326,7 @@ def main():
if __name__ == '__main__':
if any(arg in ("-h", "--help") for arg in sys.argv[1:]):
print(__doc__.strip())
sys.exit(0)
main()
+5
View File
@@ -11,9 +11,14 @@ Creates EPUBs with annotated JPEG and PNG images to verify:
"""
import os
import sys
import zipfile
from pathlib import Path
if any(arg in ("-h", "--help") for arg in sys.argv[1:]):
print(__doc__.strip())
sys.exit(0)
try:
from PIL import Image, ImageDraw, ImageFont
except ImportError: