Repository: fonttools/fonttools

Issue:
TTX hangs with (Hit any key to exit)
Hi all, and thank you very much for this tool!

I call TTX programmatically from another golang process, and once in a while it happens that ttx runs into the error. Problem is it does not error out, write and dies, but writes "(Hit any key to exit)". And I don't know how to recognize I need to send keypress to the process, nor do I know how to send that keypress to another process programmatically.

Is it possible to provide some flag or anything not to hang on this? Or what do you advise?

Thanks, Aleksandar


Discussion:
hi, thanks for the report. It appears you are running ttx on windows, am I right? There's a old feature whereby ttx forces the windows command prompt window to stay open. I think it was added because some Windows users have ttx as a batch command where they drag and drop a font on it, a new cmd.exe windows fires then closes automatically on completion, but when an error occurred you don't get to see the error message..

https://github.com/fonttools/fonttools/blob/f7653a577db40d7e7bb25e75da4df07289e67ab6/Lib/fontTools/ttx.py#L390-L396

We should probably detect whether we are running in an interactive shell session, and if not, don't wait for key press.
actually forget what I just said about interactive mode, that's something else.
We have two options: 1) remove the feature altogether (I would consider this "legacy"), or 2) add a new flag to ttx command line to opt-out from the wait for key press.
I am leaning towards option 1. /cc @justvanrossum 
ok yeah, there's a 3) option to try, which is check [`sys.stdout.isatty()`](https://docs.python.org/3/library/io.html#io.IOBase.isatty) which "Return True if the stream is interactive (i.e., connected to a terminal/tty device)." If False, don't wait for key press ('cause there can't be any).
I don't have a windows machine at hand to try this; if @bjg2 would like to give it a shot and make a PR to disable waitForKeyPress if not isatty(), you're welcome thanks!
Oh this was added a looong time ago. I wonder if @twardoch may remember. If it was because of a .bat script (on which you could drop files?), then this behavior should perhaps be part of the .bat script itself.
Hey guys, thanks for the quick turnaround!

Yes, I can confirm I am using ttx on windows. Unfortunately, I never coded in this workspace, nor do I have python setup, nor did I work in python for a long time (just one project many years ago)... I guess you would not want me just to send an untested PR with a new if, and I'm afraid it would take me a bit of disproportional amount of time to set it up and test it... Would someone else be able to pop this if inside easier?

Resolving patch:
diff --git a/Lib/fontTools/ttx.py b/Lib/fontTools/ttx.py
--- a/Lib/fontTools/ttx.py
+++ b/Lib/fontTools/ttx.py
@@ -387,15 +387,6 @@ def process(jobs, options):
 		action(input, output, options)
 
 
-def waitForKeyPress():
-	"""Force the DOS Prompt window to stay open so the user gets
-	a chance to see what's wrong."""
-	import msvcrt
-	print('(Hit any key to exit)', file=sys.stderr)
-	while not msvcrt.kbhit():
-		pass
-
-
 def main(args=None):
 	"""Convert OpenType fonts to XML and back"""
 	from fontTools import configLogger
@@ -416,16 +407,12 @@ def main(args=None):
 		log.error("(Cancelled.)")
 		sys.exit(1)
 	except SystemExit:
-		if sys.platform == "win32":
-			waitForKeyPress()
 		raise
 	except TTLibError as e:
 		log.error(e)
 		sys.exit(1)
 	except:
 		log.exception('Unhandled exception has occurred')
-		if sys.platform == "win32":
-			waitForKeyPress()
 		sys.exit(1)
 
 


Test patch:
diff --git a/Tests/ttx/ttx_test.py b/Tests/ttx/ttx_test.py
--- a/Tests/ttx/ttx_test.py
+++ b/Tests/ttx/ttx_test.py
@@ -961,10 +961,6 @@ def test_main_keyboard_interrupt(tmpdir, monkeypatch, caplog):
     assert "(Cancelled.)" in caplog.text
 
 
-@pytest.mark.skipif(
-    sys.platform == "win32",
-    reason="waitForKeyPress function causes test to hang on Windows platform",
-)
 def test_main_system_exit(tmpdir, monkeypatch):
     with pytest.raises(SystemExit):
         inpath = os.path.join("Tests", "ttx", "data", "TestTTF.ttx")
@@ -991,10 +987,6 @@ def test_main_ttlib_error(tmpdir, monkeypatch, caplog):
     assert "Test error" in caplog.text
 
 
-@pytest.mark.skipif(
-    sys.platform == "win32",
-    reason="waitForKeyPress function causes test to hang on Windows platform",
-)
 def test_main_base_exception(tmpdir, monkeypatch, caplog):
     with pytest.raises(SystemExit):
         inpath = os.path.join("Tests", "ttx", "data", "TestTTF.ttx")