-2

What are the details of your problem?

There are several ways to take external input - stdin, CLI arguments, or files, etc. In python3, keywords respectively are: input, sys.argv, open.

The most commonly used of these in normal applications is taking input from the stdin i.e. either via keyboard, or via shell; the input() function in python.

But unlike both the other 2 methods, i don't know the way to automate or hardcode this within the script be it for C/C++/Python. Some known ways to (semi) automate input seams to be stdin i.e. <<< in bash, or (as told by chatGPT) in configuration files.

This lack of automation makes it very hard while doing any type of coding, be it
designing for the first time, debugging, or benchmarking/timing.

Replacing the whole input function call with some value may work for less variables, but where lots of variables take input, it becomes laborious to add and remove such substitutes.


In continuation of this, I would like to reproduce the setup used by online coding sites like Hackerrank, Coding Ninja etc to test the script against variety of inputs.

Also to measure or cap it with time and memory limits to overcome the TLEs, but that's outside scope of this question.

  • 2
    You can replace `sys.stdin` in python with whatever you like (e.g. `open()`) by direct assignment. Does it suffice? – STerliakov May 28 '23 at 13:59
  • 2
    One way can be to redefine the `input` function by another one which returns the desired input string. – Michael Butscher May 28 '23 at 13:59
  • (though I admit I don't fully understand your question) – STerliakov May 28 '23 at 13:59
  • 1
    You could make your "tester" script run the main script using `subprocess.run`, which allows you to specify `stdin`? https://docs.python.org/3/library/subprocess.html#subprocess.run – slothrop May 28 '23 at 14:02
  • @SUTerliakov i tried `sys.stdin = '2\n5\n10'` or `sys.stdin = [2,5,10]` and in the ipython cells, still asked for input. and on the bash shell, it showed error on input() line that 'str' object has no attribute 'readline' – user8395964 May 28 '23 at 14:17
  • 1
    Does this help? https://stackoverflow.com/questions/5062895/how-to-use-a-string-as-stdin – slothrop May 28 '23 at 14:21
  • yes @slothrop `sys.stdin = io.StringIO('2\n5\n100')` worked. – user8395964 May 28 '23 at 14:28
  • @MichaelButscher i tried this, `def input(): yield io.StringIO('2') yield io.StringIO('5') yield io.StringIO('10')` (and also with normal strings), but it showed the error: `AttributeError: 'generator' object has no attribute 'strip'` as the call was `input().strip()` – user8395964 May 28 '23 at 14:30
  • `input` should just return a string. You can create a global variable holding a list of the strings to return and a global variable holding an index into the list what to return next (which is incremented by your `input`). – Michael Butscher May 28 '23 at 14:38
  • `input` is essentially just a convenience wrapper around `sys.stdin.readline`. It could be defined with something like `def input(prompt=""): print(prompt, end=''); line = sys.stdin.readline(); if line == '': raise EOFError; else return line.rstrip('\n')` Note that it is *guaranteed* not to return a value containing a newline: it always returns a *single* line with the trailing newline stripped. Any replacement needs to abide by this convention, or you run the risk of breaking code that consumes the return value of `input`. – chepner May 28 '23 at 22:42

1 Answers1

0

Combining the input in the comments with my own observation on them:

1. Directly assign the values to sys.stdin: io.StringIO
- by @SUTerliakov and @slothrop

Description:

  • colon means type annotation.
  • confirmed to work on CLI with calls like: input(), input().strip(), int( input().strip() )
  • doesn't work from .py source files' # %% ipython cells, i.e. still asks for input.
  • requires at least all the values for the input to be defined, otherwise raise error EOFError: EOF when reading a line (very similar to standard_input var in AREPL vscodium extension)
  • Example: sys.stdin = io.StringIO('2\n5\n10') will supply values to 3 input calls

Refer:

2. Redefine input() - by @MichaelButscher

  • I couldn't get it to work despite trying:
    • give normal string: return '2\n5\n10':
      ValueError: invalid literal for int() with base 10: '2\n5\n10'
    • AttributeError: 'xxxx' object has no attribute 'strip'
      (where xxxx = _io.StringIO or list or generator) when giving io.StringIO or list or yielding string:
      return io.StringIO('2\n5\n\10'):
      return ['2','5','10']
      yield '2'; yield '5'; yield '10' \

3. Use subprocess.run() - by @slothrop

Description:

  • create a separate runner/tester script, and call the main script from that script using subprocess.run() which allows passing std arguments
  • while super flexible and extensible ...
  • ~~this ain't directly executble on-the-go like shift-enter of # %% ipython cells~~
    (oh well, ctrl-tab > shift-enter)
  • but maybe there's some way to only call some function and not the whole script - if yes, then this can be used to avoid recursion and even define this runner/tester script within the main file itself.

Refer:

  • If you want to write a generator function (call it `input_gen`) that yields your desired values, then you can use it as the source of input by doing something like: `g = input_gen(); input = lambda _: next(g)` – slothrop May 29 '23 at 08:30