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
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
byexample will run the example and when it find the moment it will
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 years old
byexamplewill only recognize inputs that are at the end of a line. If an input appears in other place
byexamplewill 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
byexample 10.0.3 you can use
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
not available and you will have to use
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
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
and waits for it before start typing.
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
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
byexample may never type
the given text; if the example keeps waiting for it the example will
$ 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
not type the text; smaller prefixes on the other hand may make
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 and the input mode
>>> 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