Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 24 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,33 +359,37 @@ It is compatible with heterogeneous types. I.e.,
#### `as_list`

By default, when `read` is [called with multiple types](#multiple-tokens),
it returns a `list` with the requested tokens. If, for some reason, you
don't need implicit conversion to a `list`, `read` can return a
generator instead. This is achieved by passing `as_list=False`, as in
`read(float, amount=10000, as_list=False)`.
it returns a generator with the requested tokens. If you want the result
as a `list` instead, pass `as_list=True`, as in
`read(float, amount=10000, as_list=True)`.

This has the advantage of avoiding unnecessary iteration to create the
list and copy the tokens into it. For example, you could use it to create
a large `numpy` array:
When reading a single token (one type with `amount=1`), `read` normally
returns the token directly (e.g., an `int` or `str`). Passing
`as_list=True` will wrap the result in a list, e.g.,
`read(int, as_list=True)` returns `[5]` instead of `5`.

Using `as_list=False` (the default) has the advantage of avoiding
unnecessary iteration to create the list and copy the tokens into it.
For example, you could use it to create a large `numpy` array:

```python
import numpy as np
from easyinput import read

arr = np.array(read(float, amount=1000000, as_list=False))
arr = np.array(read(float, amount=1000000))
```

In the previous block of code, only one iteration through all of
In the previous block of code, only one iteration through all of
the tokens takes place—the one to fill the `np.array`—
whilst if `as_list` were set to
`False`, two iterations would take place: one to fill the list, and
`True`, two iterations would take place: one to fill the list, and
another to fill the array.

Keep in mind that the generator returned by `read` when `as_list` is
set to `True` *does not consume any input until you iterate through it*.
set to `False` *does not consume any input until you iterate through it*.
This is the reason for which `read_many` does **not** support this
keyword argument: it *must* consume input in order to discern
whether it should keep going or not, so it always returns
whether it should keep going or not, so it always returns
multiple-token queries as lists.

<br>
Expand Down Expand Up @@ -683,7 +687,7 @@ a.say_word()

## Interface

- *(function)* **`easyinput.read(*types, amount=1, file=_StdIn, as_list=True)`** <br>
- *(function)* **`easyinput.read(*types, amount=1, file=_StdIn, as_list=False)`** <br>
Returns tokens from the input stream specified by `file`.
`_StdIn` is an alias for standard input.

Expand All @@ -705,10 +709,13 @@ Returns tokens from the input stream specified by `file`.
(e.g. `io.StringIO`) that specifies where to read input from.

- `as_list: bool` <br>
If `True`, if more than one token is requested, converted
tokens are returned as a list, and thus input is
immediately consumed. Otherwise, a generator is
returned (and no input is consumed).
If `True`, the result is returned as a list. For single-token
reads, this wraps the token in a list (e.g., `[5]` instead of `5`).
For multiple-token reads, converted tokens are returned as a list,
and thus input is immediately consumed.
If `False` (the default), single-token reads return the token
directly, and multiple-token reads return a generator
(no input is consumed until iterated).

- *(function)* **`easyinput.read_many(*types, amount=1, file=_StdIn)`** <br>
Returns a generator that yields tokens from the input stream
Expand Down
9 changes: 6 additions & 3 deletions easyinput/tokenizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,18 +112,21 @@ def multiple_tokens(self, amount, type1=str, *types):
_StdIn = StdIn()


@kwd_only(file=_StdIn, amount=1, as_list=True) # Python 2 compatibility
@kwd_only(file=_StdIn, amount=1, as_list=False) # Python 2 compatibility
def read(*types, **kwargs):
"""
Py3 signature:
`read(*types, file:iter=_StdIn, amount:int=1, as_list:bool=True)`
`read(*types, file:iter=_StdIn, amount:int=1, as_list:bool=False)`
This function returns one or more tokens converted to
the types specified by *types.
This is the main function in the module.
"""
tokens, amount, as_list = _get_tokenizer(kwargs), _get_amount(kwargs), kwargs['as_list']
method, args = _select_method(tokens, types, amount, as_list)
return method(*args)
result = method(*args)
if as_list and not isinstance(result, list):
return [result]
return result


@kwd_only(file=_StdIn, amount=1) # Python 2 compatibility
Expand Down
14 changes: 14 additions & 0 deletions test/test_amount.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,17 @@ def test_4():
expected = ('a', 2, 'c', 3)
tokens = easyinput.read(chr, int, amount=2, file=source)
assert all(inp == val for inp, val in zip(tokens, expected))

def test_5():
source = io.StringIO("5 4 ")
expected = [5]
tokens = easyinput.read(int, amount = 1, as_list = True, file=source)
assert isinstance(tokens, list)
assert tokens == expected

def test_6():
source = io.StringIO("hello good bye")
expected = ["hello"]
tokens = easyinput.read(str, amount = 1, as_list = True, file = source)
assert isinstance(tokens, list)
assert tokens == expected