fix(e10): --e10 passed bare silently skipped the controller
Three bugs, all found by actually running the thing rather than reading it. 1. `--e10` with no value did nothing. Making the flag optional-valued gave it an empty-string constant, and the code deciding whether to drive the controller used a truth test - so the documented `--e10` form printed the full translation and quietly skipped the hardware. No error, because nothing failed. Now gated on `is not None`, with a comment saying why. 2. A missing part program dumped a traceback. The top-level handler tidied e10 errors and re-raised everything else. Now a clean message that lists the part programs it can actually see, which also covers Windows path confusion. 3. Errors could vanish when piped. stdout is block-buffered and stderr is not, so the message printed before the output it referred to and a `| tail` dropped it entirely - looking like a silent failure. stdout is flushed before writing an error.
This commit is contained in:
@@ -74,6 +74,7 @@ TRANSLATION TO THE e10
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
@@ -322,8 +323,37 @@ def main():
|
||||
for index, name in enumerate(args.var_names.split(","), start=1):
|
||||
VAR_NAMES[index] = name.strip()
|
||||
|
||||
with open(args.partprogram) as handle:
|
||||
fileinfo, general, items = parse_part_program(handle.read())
|
||||
try:
|
||||
with open(args.partprogram) as handle:
|
||||
fileinfo, general, items = parse_part_program(handle.read())
|
||||
except FileNotFoundError:
|
||||
sys.stdout.flush()
|
||||
sys.stderr.write("no such part program: %s\n" % args.partprogram)
|
||||
here = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
"..", "partprograms")
|
||||
for folder in (os.path.dirname(args.partprogram) or ".", here):
|
||||
try:
|
||||
found = sorted(f for f in os.listdir(folder)
|
||||
if f.lower().endswith(".txt"))
|
||||
except OSError:
|
||||
continue
|
||||
if found:
|
||||
sys.stderr.write("part programs in %s:\n"
|
||||
% os.path.normpath(folder))
|
||||
for name in found:
|
||||
sys.stderr.write(" %s\n" % name)
|
||||
break
|
||||
else:
|
||||
sys.stderr.write("Give the path to a .txt part program. On Windows"
|
||||
" use backslashes:\n"
|
||||
" python scripts\\simulate-ednc.py"
|
||||
" partprograms\\TEL3L0001.txt ...\n")
|
||||
sys.exit(1)
|
||||
except IsADirectoryError:
|
||||
sys.stdout.flush()
|
||||
sys.stderr.write("%s is a folder, not a part program file\n"
|
||||
% args.partprogram)
|
||||
sys.exit(1)
|
||||
|
||||
print("=" * 72)
|
||||
print("PART PROGRAM: %s" % args.partprogram)
|
||||
@@ -372,7 +402,11 @@ def main():
|
||||
else:
|
||||
print(" %-28s [%s]" % (label, payload))
|
||||
|
||||
if args.e10:
|
||||
# `is not None`, NOT a truth test. --e10 passed bare sets this to an
|
||||
# empty string, which is falsy, so a truth test silently turns a
|
||||
# hardware run into a dry run - with no error to explain why nothing
|
||||
# reached the controller.
|
||||
if args.e10 is not None:
|
||||
drive_e10(seq, args)
|
||||
|
||||
|
||||
@@ -412,4 +446,20 @@ def drive_e10(seq, args):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
try:
|
||||
main()
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(130)
|
||||
except Exception as err: # noqa: BLE001
|
||||
# E10Error is defined in the client module, which is loaded
|
||||
# dynamically, so catch by name rather than importing it up here.
|
||||
if type(err).__name__ in ("E10Error", "E10Fault"):
|
||||
# Flush stdout first. It is block-buffered when piped while stderr
|
||||
# is not, so without this the error appears BEFORE the output it
|
||||
# refers to - and a `| tail` drops it entirely, which looks like
|
||||
# the command failed silently.
|
||||
sys.stdout.flush()
|
||||
sys.stderr.write("e10: %s\n" % err)
|
||||
sys.stderr.flush()
|
||||
sys.exit(1)
|
||||
raise
|
||||
|
||||
Reference in New Issue
Block a user