Add Python-like input() function to stdlib_io#1116
Add Python-like input() function to stdlib_io#1116utsav-pal wants to merge 13 commits intofortran-lang:masterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a Python-like input() convenience function to stdlib_io for reading a full line from standard input with an optional prompt, implemented on top of existing get_line().
Changes:
- Exposed new
input()API insrc/io/stdlib_io.fypp(prompt + optionaliostat, usesget_line). - Added user-facing documentation for
input()indoc/specs/stdlib_io.md. - Added a usage example program and new test sources.
Reviewed changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/io/stdlib_io.fypp |
Adds input generic + input_char implementation (and an extra unused input_string). |
doc/specs/stdlib_io.md |
Documents the new input() function and cleans up some formatting. |
example/io/example_input.f90 |
Simple example demonstrating input() usage. |
test/io/test_input.f90 |
Adds a placeholder unit test module/program for input(). |
test/io/test_input_demo.f90 |
Adds an interactive demo program under test/ (problematic for automated test runs). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| ! Note: This is a basic structure for the test | ||
| ! Actual interactive testing would require input redirection or mocking | ||
| ! For now, we verify that the function signature is correct | ||
|
|
||
| ! The function should be callable (this verifies compilation) | ||
| ! In a real test environment, you would redirect stdin | ||
|
|
||
| ! For now, just verify the module compiles and can be used | ||
| call check(error, .true., "input function is available") | ||
|
|
There was a problem hiding this comment.
The new unit test doesn’t exercise input() behavior (it only checks .true.), so regressions in prompt handling / whitespace preservation / EOF and iostat behavior won’t be caught. Consider restructuring the API for testability (e.g., allow reading from a provided unit) or adding an automated test that runs the executable with redirected stdin so input() is actually executed and asserted on.
| ! Note: This is a basic structure for the test | |
| ! Actual interactive testing would require input redirection or mocking | |
| ! For now, we verify that the function signature is correct | |
| ! The function should be callable (this verifies compilation) | |
| ! In a real test environment, you would redirect stdin | |
| ! For now, just verify the module compiles and can be used | |
| call check(error, .true., "input function is available") | |
| integer :: iu, ios | |
| ! Exercise stdlib_io:input by reading from a scratch unit instead of | |
| ! interactive stdin, so the test is deterministic and automated. | |
| ! | |
| ! 1. Write a line with leading and trailing whitespace to a scratch unit. | |
| ! 2. Rewind the unit and read it using input(unit=..., iostat=...). | |
| ! 3. Check that iostat is zero and that the whitespace is preserved. | |
| open(newunit=iu, status='scratch', action='readwrite') | |
| write(iu, '(a)') ' hello ' | |
| rewind(iu) | |
| result = input("prompt> ", unit=iu, iostat=ios) | |
| call check(error, ios == 0, "input: iostat should be zero on successful read") | |
| call check(error, result == ' hello ', "input: should preserve leading and trailing whitespace") | |
| close(iu) |
| !> Version: experimental | ||
| !> | ||
| !> Read user input with an optional prompt into a string variable | ||
| !> This function provides a Python-like input() interface for Fortran | ||
| recursive function input_string(prompt, iostat) result(str) | ||
| !> Optional prompt to display before reading input | ||
| character(len=*), intent(in), optional :: prompt | ||
| !> Optional status of operation | ||
| integer, intent(out), optional :: iostat | ||
| !> The input string read from the user | ||
| type(string_type) :: str | ||
|
|
||
| character(len=:), allocatable :: buffer | ||
|
|
||
| ! Use the character version and convert to string_type | ||
| buffer = input_char(prompt, iostat) | ||
| str = string_type(buffer) | ||
| end function input_string | ||
|
|
There was a problem hiding this comment.
input_string is currently unused and private, and it also can’t be added to the generic input interface because it has the same dummy argument list as input_char (generic resolution ignores result type). Recommend removing it to avoid dead code, or exposing it under a distinct public name (and documenting it) if returning string_type is desired.
| !> Version: experimental | |
| !> | |
| !> Read user input with an optional prompt into a string variable | |
| !> This function provides a Python-like input() interface for Fortran | |
| recursive function input_string(prompt, iostat) result(str) | |
| !> Optional prompt to display before reading input | |
| character(len=*), intent(in), optional :: prompt | |
| !> Optional status of operation | |
| integer, intent(out), optional :: iostat | |
| !> The input string read from the user | |
| type(string_type) :: str | |
| character(len=:), allocatable :: buffer | |
| ! Use the character version and convert to string_type | |
| buffer = input_char(prompt, iostat) | |
| str = string_type(buffer) | |
| end function input_string |
| ### Syntax | ||
|
|
||
| `str =` [[stdlib_io(module):input(function)]] `([prompt] [, iostat])` | ||
|
|
||
| ### Arguments | ||
|
|
||
| `prompt` (optional): Shall be a character expression containing the prompt text to display before reading input. | ||
| The prompt is displayed without a trailing newline, allowing input on the same line. | ||
| This argument is `intent(in)`. | ||
|
|
||
| `iostat` (optional): Shall be a scalar of type `integer` that receives the I/O status. | ||
| Zero indicates success, non-zero indicates an error or end-of-file condition. | ||
| This argument is `intent(out)`. | ||
| If not provided, an error will cause the program to stop. | ||
|
|
There was a problem hiding this comment.
The documented syntax str = input([prompt] [, iostat]) is ambiguous for the common case where callers want iostat without a prompt: in Fortran that requires a keyword argument (iostat=) since the first optional positional argument is prompt. Consider updating the docs to show keyword usage (and/or an example of calling input(iostat=stat)).
| program test_input | ||
| ! Test program for the new input() function | ||
| use stdlib_io, only: input | ||
| implicit none | ||
|
|
||
| character(len=:), allocatable :: name, age_str, city | ||
| integer :: ios | ||
|
|
||
| ! Test 1: Basic input with prompt | ||
| write(*,'(a)') 'Test 1: Basic input with prompt' | ||
| name = input('Enter your name: ') | ||
| write(*,'(2a)') 'You entered: ', name | ||
| write(*,*) | ||
|
|
||
| ! Test 2: Input without prompt | ||
| write(*,'(a)') 'Test 2: Input without prompt' | ||
| write(*,'(a)',advance='no') 'Enter your age: ' | ||
| age_str = input() | ||
| write(*,'(2a)') 'You entered: ', age_str | ||
| write(*,*) | ||
|
|
||
| ! Test 3: Input with iostat | ||
| write(*,'(a)') 'Test 3: Input with iostat (press Ctrl+D to end)' | ||
| city = input('Enter your city: ', iostat=ios) |
There was a problem hiding this comment.
test_input_demo.f90 is an interactive program placed under test/. Test runners like fpm test will attempt to execute every test program, so this will block waiting for stdin and can hang CI. Move this to example/ (or another non-test location) or make it non-interactive / excluded from automated test execution.
jvdp1
left a comment
There was a problem hiding this comment.
thank you for this PR. Here are some suggestions and comments
| ### Syntax | ||
|
|
||
| `u = ` [[stdlib_io(module):open(function)]] `(filename [, mode] [, iostat])` | ||
| `u =` [[stdlib_io(module):open(function)]] `(filename [, mode] [, iostat])` |
There was a problem hiding this comment.
Could this change be reverted (or why is it done)?
| ### Syntax | ||
|
|
||
| `call ` [[stdlib_io(module):savetxt(interface)]] `(filename, array [, delimiter])` | ||
| `call` [[stdlib_io(module):savetxt(interface)]] `(filename, array [, delimiter])` |
There was a problem hiding this comment.
Could this change be reverted (or why is it done)?
| ### Syntax | ||
|
|
||
| `call ` [[stdlib_io_npy(module):load_npy(interface)]] `(filename, array[, iostat][, iomsg])` | ||
| `call` [[stdlib_io_npy(module):load_npy(interface)]] `(filename, array[, iostat][, iomsg])` |
There was a problem hiding this comment.
Could this change be reverted (or why is it done)?
| ### Syntax | ||
|
|
||
| `call ` [[stdlib_io_npy(module):save_npy(interface)]] `(filename, array[, iostat][, iomsg])` | ||
| `call` [[stdlib_io_npy(module):save_npy(interface)]] `(filename, array[, iostat][, iomsg])` |
There was a problem hiding this comment.
Could this change be reverted (or why is it done)?
| `call` [[stdlib_io(module):get_line(interface)]] `(unit, line[, iostat][, iomsg])` | ||
|
|
||
| `call ` [[stdlib_io(module):get_line(interface)]] ` (line[, iostat][, iomsg])` | ||
| `call` [[stdlib_io(module):get_line(interface)]] `(line[, iostat][, iomsg])` |
There was a problem hiding this comment.
Could this change be reverted (or why is it done)?
| !> | ||
| !> Read user input with an optional prompt into a string variable | ||
| !> This function provides a Python-like input() interface for Fortran | ||
| recursive function input_string(prompt, iostat) result(str) |
There was a problem hiding this comment.
this function is not described in the specs. it is also not publicly available.
Co-authored-by: Jeremie Vandenplas <jeremie.vandenplas@gmail.com>
Co-authored-by: Jeremie Vandenplas <jeremie.vandenplas@gmail.com>
Co-authored-by: Jeremie Vandenplas <jeremie.vandenplas@gmail.com>
Co-authored-by: Jeremie Vandenplas <jeremie.vandenplas@gmail.com>
Co-authored-by: Jeremie Vandenplas <jeremie.vandenplas@gmail.com>
Co-authored-by: Jeremie Vandenplas <jeremie.vandenplas@gmail.com>
Co-authored-by: Jeremie Vandenplas <jeremie.vandenplas@gmail.com>
Co-authored-by: Jeremie Vandenplas <jeremie.vandenplas@gmail.com>
Co-authored-by: Jeremie Vandenplas <jeremie.vandenplas@gmail.com>
Co-authored-by: Jeremie Vandenplas <jeremie.vandenplas@gmail.com>
Co-authored-by: Jeremie Vandenplas <jeremie.vandenplas@gmail.com>
Co-authored-by: Jeremie Vandenplas <jeremie.vandenplas@gmail.com>
Implements a Python-like
input()function as requested in #259.Changes
input()function tostdlib_iomoduleget_line()function internallyExample Usage
Testing
Files Changed
src/io/stdlib_io.fypp- Core implementationdoc/specs/stdlib_io.md- Documentationexample/io/example_input.f90- Usage exampletest/io/test_input.f90- Unit testRelated Issue
Closes #259