From 523fd954098b7dace00f4612382a065e5cefb393 Mon Sep 17 00:00:00 2001 From: Martin Di Paola Date: Mon, 16 Mar 2026 20:54:51 -0300 Subject: [PATCH 1/3] fix: try turn echo off multiple times --- byexample/runner.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/byexample/runner.py b/byexample/runner.py index d4d4e20..62f5796 100644 --- a/byexample/runner.py +++ b/byexample/runner.py @@ -576,6 +576,9 @@ def _exec_and_wait(self, source, options, *, from_example=None, **kargs): self._last_num_lines_sent = 0 for line in lines[:-1]: with profile_ctx("sendline"): + # turn the echo off (may be) + self._may_turn_echo_off(options) + self._sendline(line) self._last_num_lines_sent += 1 self._expect_prompt_or_type( @@ -583,6 +586,9 @@ def _exec_and_wait(self, source, options, *, from_example=None, **kargs): ) with profile_ctx("sendline"): + # turn the echo off (may be) + self._may_turn_echo_off(options) + self._sendline(lines[-1]) self._last_num_lines_sent += 1 From 98c01cddfa58fa993f04995bc5d1d36620d15626 Mon Sep 17 00:00:00 2001 From: Martin Di Paola Date: Mon, 16 Mar 2026 20:55:00 -0300 Subject: [PATCH 2/3] feat: trace what lines we sent to the interpreter --- byexample/runner.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/byexample/runner.py b/byexample/runner.py index 62f5796..da2e3a4 100644 --- a/byexample/runner.py +++ b/byexample/runner.py @@ -573,6 +573,10 @@ def _exec_and_wait(self, source, options, *, from_example=None, **kargs): countdown = Countdown(timeout) lines = source.split('\n') + if clog().isEnabledFor(DEBUG): + with log_with("sendlines") as clog2: + clog2.debug("\n > " + '\n > '.join(lines)) + self._last_num_lines_sent = 0 for line in lines[:-1]: with profile_ctx("sendline"): From d563072ff022c253c3299bc4cdede1064bb3a3c6 Mon Sep 17 00:00:00 2001 From: Martin Di Paola Date: Mon, 16 Mar 2026 23:49:01 -0300 Subject: [PATCH 3/3] fix: set TERM=dumb by default [break] Different interpreters may behave in a simpler way (no fancy terminal escape code, no colors, no cursor movements) if they detect that the terminal does not support it. For this, the TERM env var is used and traditionally, the "dumb" terminal signals the simplest terminal possible. This change may break tests if they relay on having a different TERM. For example, in executing `less` in bash (shell language) will emit an ugly warning because the terminal is not functional. More: - feat: add +term-type to control TERM env (for all interpreters, like +geometry) - fix: term emulation's tests - doc: the new +term-type and how to run a test as in prev versions --- byexample/init.py | 6 ++++ byexample/runner.py | 7 ++++ docs/advanced/terminal-emulation.md | 51 ++++++++++++++++++++++++++--- 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/byexample/init.py b/byexample/init.py index 6487e84..bb5cc13 100644 --- a/byexample/init.py +++ b/byexample/init.py @@ -443,6 +443,12 @@ def get_default_options_parser(cmdline_args): help= "select a terminal emulator to interpret the output (default to 'dumb')." ) + options_parser.add_argument( + "+term-type", + default='dumb', + help= + "set the TERM env var for the interpreters/runners (default to 'dumb', other values could be 'vt100'); if left empty, leave it unset." + ) options_parser.add_flag( "type", diff --git a/byexample/runner.py b/byexample/runner.py index da2e3a4..68c7a14 100644 --- a/byexample/runner.py +++ b/byexample/runner.py @@ -348,8 +348,15 @@ def _spawn_interpreter( env = os.environ.copy() if env_update: env.update(env_update) + + # Override the environment with LINES, COLUMNS (from geometry) env.update({'LINES': str(rows), 'COLUMNS': str(cols)}) + # With TERM=dumb is the safest option, TERM=vt100 may be needed to offer a dummy + # *but* functional TERM because some programs may print scary "WARNING: terminal is not fully functional" + term_kind = options['term_type'].strip() + env.update({'TERM': term_kind}) + self._drop_output() # there shouldn't be any output yet but... self._cmd = cmd diff --git a/docs/advanced/terminal-emulation.md b/docs/advanced/terminal-emulation.md index c7a60fb..d8d789a 100644 --- a/docs/advanced/terminal-emulation.md +++ b/docs/advanced/terminal-emulation.md @@ -17,7 +17,6 @@ is fast and works well in most cases. But you can change this to disable emulation with ``+term=as-is`` or to enable full ANSI terminal emulation with ``+term=ansi``. - ## Dumb terminal In this mode, ``byexample`` emulates a very simple terminal, processing @@ -104,9 +103,9 @@ It can be useful in some special cases to check white spaces that are removed by the dumb or ANSI terminals. ```python ->>> print("\tfoo\tbar\nbaz\tsaz \rtaz") # byexample: +term=as-is +>>> print("\tfoo\tbar\nbaz\tsaz\rtaz") # byexample: +term=as-is foo bar -baz saz +baz saz taz ``` @@ -163,7 +162,7 @@ that use ``ncurses``) and require a terminal emulator. Examples of this are programs like ``less``, ``more``, ``top`` and ``man``. ```shell -$ less test/ds/python-tutorial.v2.md # byexample: +term=ansi +rm=  +stop-on-timeout +$ TERM=vt100 less test/ds/python-tutorial.v2.md # byexample: +term=ansi +rm=  +stop-on-timeout  This is a 101 Python tutorial  The following is an example written in Python about arithmetics   @@ -212,6 +211,50 @@ line 32 If this is a problem change the [geometry](/{{ site.uprefix }}/advanced/geometry): increase the count of rows that the terminal has with ``+geometry``. +## ``TERM`` environment variable + +While the ``+term`` controls how the *output* is emulated and can be +changed per example, ``byexample`` also sets the ``TERM`` environment +variable to indicate the interpreter (and possible any subprogram +executed by it) that the terminal if of a particular type. + +Contrary to ``+term``, ``+term-type`` has effect only if it is set +in the command line before the interpreters are started and it cannot be +changed later. + +By default, ``byexample`` sets ``TERM=dumb`` to indicate a +zero-capabilites terminal. You can change this setting from +the command line with ``-o +term-type=vt100`` (``vt100`` indicates a +basic but functional terminal). + +```shell +$ byexample -l shell test/ds/echo-term-env-variable.md +<...> +TERM=dumb +<...> + +$ byexample -l shell -o +term-type=vt100 test/ds/echo-term-env-variable.md +<...> +TERM=vt100 +<...> +``` + +If you want to use the same ``TERM`` value that your real terminal has, +you can pass it (nothing special is needed): + +```shell +$ TERM=xterm +$ byexample -l shell -o +term-type=$TERM test/ds/echo-term-env-variable.md +<...> +TERM=xterm +<...> +``` + +> *Changed* in `byexample 11.0.0`. Before `11.0.0.` the `TERM` variable +> was inherit from the caller's environment. Starting from `11.0.0` +> this is not longer the case. If you need the old behavior, +> do `-o +term-type=$TERM` as shown above. +