Skip to content

Instantly share code, notes, and snippets.

@therealzanfar
Last active January 2, 2024 01:13
Show Gist options
  • Save therealzanfar/4df3a774c2d7b5f51c8775d38dd8ef37 to your computer and use it in GitHub Desktop.
Save therealzanfar/4df3a774c2d7b5f51c8775d38dd8ef37 to your computer and use it in GitHub Desktop.
Useful Python utility functions
class Coord2:
"""
A 2-dimensional Coordinate.
"""
import re
from typing import TypeVar, Callable
T = TypeVar("VT")
def input_validate(
prompt: str = "",
type_: Callable[str]] T] = str,
validate: str | re.Pattern | Callable[[T], bool] | None = None,
error: str = r"Invalid input, please try again ({e!s})",
) -> T:
"""
Return validated user input.
The user is prompted for input using `prompt`, that input is cast to
`type_`, validated with `validate`, and returned. If the input violates
either the type cast or validation, then the user will alerted with
`error` and be re-promted
Args:
prompt (str, optional): The input prompt to present to the user.
Passed directly to `input`. Defaults to "".
type_ (Callable[str]] T], optional): A function that will cast a
`str` to the desired type. Most builtin types will suffice.
Defaults to `str`.
validate (str | re.Pattern | Callable, optional):
Method to validate the user input: a regular expression as a `str`
or a compiled `Pattern`, or any function that accepts an argument
of type `type_` and returns a `bool`. If omitted, no additional
validation is performed. Defaults to None (no validation).
error (str, optional): The error message to print on failed
validation. Will be formatted with the validation exception passed
as `e`. Defaults to r"Invalid input, please try again ({e!s})".
Returns: T
The validated input as type `type_`.
"""
while True:
raw_input = input(prompt)
try:
cast_input = type_(raw_input)
except ValueError as e:
print(error.format(e=e))
continue
if isinstance(validate, str):
validate = re.compile(validate)
if isinstance(validate, re.Pattern):
if not validate.match(str(cast_input)):
print(error.format(e="Input failed validation"))
continue
elif callable(validate):
if not validate(cast_input):
print(error.format(e="Input failed validation"))
continue
return cast_input
from collections import deque
from typing import TypeVar, Iterable, Iterator
T = TypeVar("T")
def window(i: Iterable[T], size: int = 2) -> Iterator[tuple[T, ...]]:
"""
Yield a sliding window of items from an iterator.
If size is 2, then the first tuple will contain the first and second
items, the second tuple will contain the second and third items, the third
tuple will contain the third and fourth items, and so on until the last
tuple will contain the second-to-last and last items.
If size is less than the length of the iterator, then a single tuple will
be yielded containing all items.
Args:
i (Iterable[T]): The iterable over which to window.
size (int, optional): The number of items in the window.
Defaults to 2.
Returns: Iterator[tuple[T, ...]]
An iterator of tuples of length `size`, each containing consecutive
items from `i`.
"""
i: Iterable[T] = iter(i)
w: deque[T] = deque()
qsize = max(1, size)
for _ in range(qsize):
try:
w.append(next(i))
except StopIteration:
yield tuple(w)
return
yield tuple(w)
for e in i:
w.append(e)
w.popleft()
yield tuple(w)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment