George's Utils
I made some utils and put them in a centralized place.
Install with uv pip install georges-utils.
utils
AutoId
Bases: Generic[T]
A class that has a global id that can be reset and incremented.
It defaults to using the natural numbers (0, 1, 2, ...) but this can be overridden.
If the type parameter is changed, the _increment_id and _id_default_value methods need to be updated.
Source code in utils/auto_id.py
next_id()
classmethod
Generate the next id.
The default behavior is to increment the current id (and return the old one).
However, this can be changed by overriding _increment_global_id.
Source code in utils/auto_id.py
reset_global_id()
classmethod
Reset the global id of this class to the default. It does not affect subclasses.
todo(*args)
Raises a NotImplementedYetError, which is a subclass of a NotImplementedError.
Any additional args will be passed into the error.
unimplemented(*args)
Raises a NotImplemented error.
Any additional args will be passed into the error.
unreachable(*args)
Raises an UnreachableError, which is a subclass of an AssertionError.
Any additional args will be passed into the error.
utils.NotImplementedYetError
Bases: NotImplementedError
Source code in utils/errors.py
utils.UnreachableError
Bases: AssertionError
Source code in utils/errors.py
utils.cached_iterator
cached_iterator(fn)
Cache an iterator by storing all the resulting elements as a tuple.
This works as on plain functions, or as an instance method, property, classmethod or other descriptor.
This uses functools.lru_cache to implement the cache and so methods such as cache_clear are still valid.
Example use:
from typing import Generator
from utils import cached_iterator
@cached_iterator
def squares(n: int) -> Generator[int]:
for i in range(1, n + 1):
yield i ** 2
assert squares(5) == (1, 4, 9, 16, 25)
assert squares(5) is squares(5) # cached
Source code in utils/cached_iterator.py
utils.compose
compose(f, g)
Combine functions f and g to f.g where f.g(x) = f(g(x)).
utils.identity
utils.increment
utils.decrement
utils.min_max
min_max(a, b, /, *, key=None)
Return the min and the max of two items as a tuple. The first item in the min and the second is the max. It is also possible to specify a key which is used for comparison. In the case of a tie, the original order is maintained. For example:
>>> from utils import min_max
>>> min_max(0, 5)
(0, 5)
>>> min_max(0.5, 0.1)
(0.1, 0.5)
>>> import operator
>>> min_max(10, 5, key=operator.neg) # compare by lambda x: -x
(10, 5)
>>> min_max("gfed", "cba", key=lambda _: 0)
('cfed', 'cba')
Source code in utils/min_max.py
utils.round
round(x)
Round the value to the nearest integer.
When n is a natural number,
- n + 0.5 rounds to n + 1
- -n - 0.5 rounds to -n
For example:
builtins.round.
Source code in utils/round.py
utils.plugins.pytest_plugin
This contains a collection of helpful pytest fixtures. They are automatically loaded when this module is installed.
filepath(filename)
Convert a filename parameter as a string into a Path.
For example:
import pytest
from pathlib import Path
@pytest.mark.parametrize(
"filename, contents",
[
("log.txt", "log_data"),
("scores.json", '{"player_1": 1, "player_2": 2}'),
]
)
def test_simplification(filepath: Path, contents: str) -> None:
assert filepath.read_text() == contents
Source code in utils/plugins/pytest_plugin.py
manual_seed(seed)
Automatically seed random generators. Use this by defining the seed parameter or fixture. In this example, each test has a different seed:
import pytest, random
@pytest.mark.parametrize("seed", range(5))
def test_random_generation(seed: int) -> None:
result = [random.random() for _ in range(10)]
Source code in utils/plugins/pytest_plugin.py
reset_global_id()
setup_debug()
Setup dbg.
This will put dbg into builtins so it can be used when testing without an import.
It also sorts any unordered collections to make understanding test failures easier when using pytest-dbg.