Type Text
There are cases when an example requires input from the user like when you are running an interactive code or command.
Starting from 9.1.0, byexample
allows you to type text.
This is enabled with +input
and starting from 10.0.3 you
can enable it with +type
.
Imagine the following scenario where an example requests your name:
>>> name = input("your name please: ") # byexample: +type
your name please: [john]
The example works as usual with two peculiarities: first we
enable the typing mode with +type
and second we write between
brackets the text that we want to type like [john]
.
byexample
will run the example and when it find the moment it will
write john
to the standard input.
>>> print(name)
john
Here is an example that ask several things at once:
>>> def ask():
... n = input("name: ")
... print("Nice to meet you %s!" % n)
... a = input("age: ")
... print("%s years old" % a)
>>> ask() # byexample: +type
name: [john]
Nice to meet you john!
age: [42]
42 years old
Note:
byexample
will only recognize inputs that are at the end of a line. If an input appears in other placebyexample
will let you know and issue a warning.
Warning: typing something when the example is not waiting for an input is undefined. Most probably the typed text will be forwarded to the underlying runner or interpreter, it may be partially executed and most likely will break the synchronization with
byexample
. Not fun.
And here is an example that read three lines in a row: this is how you need to input a text that spans more than one line.
>>> import sys
>>> def read_lines(num):
... lines = []
... for cnt, line in enumerate(sys.stdin, 1):
... lines.append("recv: " + line)
... if cnt == num:
... break
... print(''.join(lines))
>>> read_lines(3) # byexample: +type
[hello]
[my name is John]
[how are you?]
recv: hello
recv: my name is John
recv: how are you?
Alias: +input / +type
Starting from byexample 10.0.3
you can use +type
or +input
to enable this feature. Both are the same.
>>> name = input("your name please: ") # byexample: +type
your name please: [john]
>>> print(name)
john
>>> name = input("your name please: ") # byexample: +input
your name please: [joanna]
>>> print(name)
joanna
If you are using an older version of byexample
, +type
will
not available and you will have to use +input
.
Support
Input is an experimental feature: any kind of comments are welcome.
Don’t be afraid to open an issue in Github.
See the documentation page of each language for more information.
The Input Prefix
When byexample
finds a [text]
it knows that it needs to type
the that text but it does not know when it should do it.
Some runners/interpreters are sensible to this and typing the text before the right moment may make them to ignore the text.
For this reason byexample
uses the text that appears before [text]
and waits for it before start typing.
In general byexample
is smart enough to keep all of this behind scenes
however, when a capture tag is found, byexample
requires at minimum
of text before the input tag and if there is not enough it will complain:
$ cat test/ds/minimum-ctx-input.md # byexample: +rm=
<...>
>>> x = input("say: ") # byexample: +type
sa<...>y: [foo]
>>> x
'foo'
<...>
$ byexample -l python test/ds/minimum-ctx-input.md
<...>=> Parse of example 1 of 2 failed.
ValueError: There are too few characters (3) before the input tag at character 10th to proceed
<...>
[ABORT] Pass: 0 Fail: 0 Skip: 0
In these cases byexample
requires a minimum of prefix.
In other cases, byexample
may use too much of the text before [text]
:
it may wait for too large text before start typing.
This can be a problem if the text that you are expecting does not match with the output of the example.
If the mismatch happen too close to [text]
, byexample
may never type
the given text; if the example keeps waiting for it the example will
eventually timeout:
$ cat test/ds/maximum-ctx-input.md # byexample: +rm=
<...>
>>> x = input("Some large text: ") # byexample: +type
Some typo! text: [foo]
>>> x
'foo'
<...>
$ byexample -l python test/ds/maximum-ctx-input.md
<...>=> Execution timedout at example 1 of 2.
- This could be because the example just ran too slow (try add more time
with +timeout=<n>) or the example is "syntactically incorrect" and
the interpreter hang (may be you forgot a parenthesis or something like that?).
- This happen before typing 'foo'.
Perhaps the text before did not match what you expected?
typo! text:
- This is the last output obtained:
Some large text:
<...>
[ABORT] Pass: 0 Fail: 1 Skip: 0
Of course the problem is that the expected and the got outputs are different
(typo! text:
and Some large text:
respectively) and it should be fixed
in the first place but because byexample
will not
type anything that may generate more mismatches later which makes
the whole thing more difficult to understand.
byexample
uses a maximum
of prefix to control this: larger prefixes
increase the probability of having a mismatch and making byexample
to
not type the text; smaller prefixes on the other hand may make byexample
to type the text sooner and the example could ignore it.
Both minimum and maximum can be controlled by an option per example or globally:
$ byexample -l python -o '+input-prefix-range=3:12' test/ds/minimum-ctx-input.md
<...>
[PASS] Pass: 2 Fail: 0 Skip: 0
$ byexample -l python -o '+input-prefix-range=4:4' test/ds/maximum-ctx-input.md
<...>
Expected:
Some typo! text: [foo]
Got:
Some large text: [foo]
<...>
Input a Pasted Text
It is perfectly possible to capture a text in one example and use it as input for another.
The only thing you need is to enable the
paste mode
+paste
and the input mode +type
.
>>> 42
<magic>
>>> n = input("a number please: ") # byexample: +paste +type
a number please: [<magic>]
>>> s = input("a password: ") # byexample: +paste +type
a password: [admin<magic>!]
>>> n
'42'
>>> s
'admin42!'
Warning: pasting inside an input tag is okay, capturing is not. It makes no sense. This could happen by accident if the tag you are using did not capture anything before, it is new or you forgot to enable the paste mode with
+paste
.