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 argparse
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@@ -322,8 +323,37 @@ def main():
|
|||||||
for index, name in enumerate(args.var_names.split(","), start=1):
|
for index, name in enumerate(args.var_names.split(","), start=1):
|
||||||
VAR_NAMES[index] = name.strip()
|
VAR_NAMES[index] = name.strip()
|
||||||
|
|
||||||
|
try:
|
||||||
with open(args.partprogram) as handle:
|
with open(args.partprogram) as handle:
|
||||||
fileinfo, general, items = parse_part_program(handle.read())
|
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("=" * 72)
|
||||||
print("PART PROGRAM: %s" % args.partprogram)
|
print("PART PROGRAM: %s" % args.partprogram)
|
||||||
@@ -372,7 +402,11 @@ def main():
|
|||||||
else:
|
else:
|
||||||
print(" %-28s [%s]" % (label, payload))
|
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)
|
drive_e10(seq, args)
|
||||||
|
|
||||||
|
|
||||||
@@ -412,4 +446,20 @@ def drive_e10(seq, args):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
main()
|
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