๐ฒ simplibs-randomize
Generate realistic test data effortlessly from Type Hints.
A zero-friction Python library for generating randomized mock values directly from type annotations, custom domain types, and generic structures. Fully configurable, extensible, and isolated.
from simplibs.randomize import randomize
randomize(int) # -> 42
randomize(list[str]) # -> ["alpha", "bravo", "charlie"]
randomize(dict[str, Union[int, bool]]) # -> {"key_x": 105, "key_y": True}
๐งญ The Core Philosophy
Writing realistic test fixtures or mock data generation code is often tedious and error-prone. Developers repeatedly build ad-hoc custom generators or wrestle with overly rigid mocking frameworks.
simplibs-randomize bridges this gap by acting as a Type-Aware Randomization
Engine. Pass any standard Python type, generic type hint (Union, Literal,
Optional), or custom class, and receive a valid instance instantly. It ships with a
single, ready-to-use global registry for everyday defaults while giving you
fine-grained, context-safe local overrides whenever your tests demand precision.
๐ฆ Installation
pip install simplibs-randomize
๐ Quick Start in 60 Seconds
Level 1: Standalone Generators
Every randomizer can be called directly and independently โ no setup required, and every parameter is optional.
from simplibs.randomize import randomize_int, randomize_str
age = randomize_int(min_value=18, max_value=99)
username = randomize_str(min_length=5, max_length=12)
Level 2: Type-Driven Generation
Don't want to remember which function belongs to which type? Pass any type hint to
randomize() and let the library figure out the rest โ including nested, generic
structures.
from simplibs.randomize import randomize
user_id = randomize(int)
tags = randomize(list[str])
payload = randomize(dict[str, list[Union[int, bool]]])
Level 3: Bulk Generation
Need several values at once? bulk_randomizer handles both positional and
dictionary-shaped requests.
from simplibs.randomize import bulk_randomizer
payload = bulk_randomizer({
"user_id": int,
"username": (str, {"min_length": 5}),
"is_active": bool,
})
# -> {"user_id": 482, "username": "aX9qL", "is_active": True}
๐ ๏ธ The Architecture: 3 Pillars
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Randomizers โ โโโ Standalone & type-aware generator functions
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Registry โ โโโ RANDOMIZERS singleton, RegistryBase, LocalRegistry
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Core Functions โ โโโ get_randomizer, randomize, bulk_randomizer
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
1. Randomizers (The Generators)
Every value-generating function in the library, grouped into Standalone (primitives, special, temporal), Type-Aware (collections, structural), and Meta types โ each documented individually with parameters, defaults, examples, and full source.
โก๏ธ README_DEFAULT_RANDOMIZERS
Every one of them is also indexed in the quick-reference table below.
2. Registry (The Storage & Scoping Layer)
The system that maps types to randomizer callables, resolves user overrides before falling back to defaults, and supports fully isolated local scopes via context managers.
-
RegistryBaseโ the shared abstract foundation (MutableMapping+ context-manager logic).
โก๏ธ README_REGISTRY_BASE -
RandomizersRegistryโ the concrete class behind the globalRANDOMIZERSsingleton, also usable as a fully standalone registry.
โก๏ธ README_RANDOMIZERS_REGISTRY -
LocalRegistryโ isolated, scoped overrides with transparent global fallback.
โก๏ธ README_LOCAL_REGISTRY -
The
RANDOMIZERSsingleton & context state (_CURRENT_REGISTRY,get_current_registry) โ how the active registry is resolved automatically, everywhere in the library.
โก๏ธ README_STATE -
ALL_DEFAULTโ the full built-in dictionary structure every registry falls back to.
โก๏ธ randomizers/README_ALL_DEFAULT
3. Core Functions (The Entry Points)
The three top-level functions tying everything together: get_randomizer (resolution),
randomize (resolution + execution), and bulk_randomizer (batch processing).
โก๏ธ README_MAIN_FUNCTIONS
๐ Randomizer Quick Reference
Every built-in randomizer, its parameters, and their defaults. For the full description, examples, and implementation of each one, see README_DEFAULT_RANDOMIZERS.
1. Standalone Randomizers
1.1 Primitives
| - - - - - Randomizer - - - - - | - - - - - - - - - - Parameters (default) - - - - - - - - - - |
|---|---|
randomize_bool |
true_probability: float = 0.5 |
randomize_bytes |
min_length: int = 5max_length: int = 15 |
randomize_decimal |
min_value: float = 0.0max_value: float = 1000.0exponent: int = -2 |
randomize_float |
min_value: float = 0.0max_value: float = 1000.0ndigits: int = 2 |
randomize_int |
min_value: int = 0max_value: int = 1000 |
randomize_str |
min_length: int = 5max_length: int = 15alphabet: str = ascii_letters + digits |
1.2 Special
| - - - - - Randomizer - - - - - | - - - - - - - - - - Parameters (default) - - - - - - - - - - |
|---|---|
randomize_path |
directory: str = "/tmp"extension: str = ".txt"name_length: int = 10 |
randomize_uuid |
โ (no parameters) |
1.3 Temporal
| - - - - - Randomizer - - - - - | - - - - - - - - - - Parameters (default) - - - - - - - - - - |
|---|---|
randomize_date |
start: date = date(2020, 1, 1)end: date = date(2025, 12, 31) |
randomize_datetime |
start: datetime = datetime(2020, 1, 1)end: datetime = datetime(2025, 12, 31) |
randomize_time |
min_hour: int = 0max_hour: int = 23 |
randomize_timedelta |
min_seconds: int = 0max_seconds: int = 2592000 (30 days) |
2. Type-Aware Randomizers
2.1 Collections
| - - - - - Randomizer - - - - - | - - - - - - - - - - Parameters (default) - - - - - - - - - - |
|---|---|
randomize_dict |
dict_type: Any = dictmin_length: int = 1max_length: int = 5 |
randomize_list |
list_type: Any = listmin_length: int = 1max_length: int = 5 |
randomize_set |
set_type: Any = set[str]min_length: int = 1max_length: int = 5max_attempts: int = 50 |
randomize_tuple |
tuple_type: Any = tuplemin_length: int = 1max_length: int = 5 |
2.2 Structural
| - - - - - Randomizer - - - - - | - - - - - - - - - - Parameters (default) - - - - - - - - - - |
|---|---|
randomize_enum |
enum_type: type[Enum] = Enumexclude: Iterable[Enum] | None = None |
randomize_literal |
literal_type: Any = Literal |
randomize_union |
union_type: Any = UnionTypenone_probability: float = 0.3 |
3. Meta Types
| - - - - - Randomizer - - - - - | - - - - - - - - - - Parameters (default) - - - - - - - - - - |
|---|---|
randomize_any |
*choices: Anyvalidate: bool = True |
get_none |
โ (no parameters) |
๐๏ธ The RANDOMIZERS Singleton & Registry Classes
Every randomizer lookup goes through a registry. By default, that's the global
RANDOMIZERS singleton โ a ready-to-use instance you can treat as a dictionary, or
manage through explicit helper functions:
from simplibs.randomize.registry import RANDOMIZERS, add_randomizer
# Dictionary-style
RANDOMIZERS[str] = lambda: "custom-value"
# Or via the exported helper functions
add_randomizer(str, lambda: "custom-value")
When you need isolation โ in tests, or for a specific code path โ LocalRegistry lets
you override behavior temporarily without touching the global state, while still
transparently seeing any global overrides:
from simplibs.randomize.registry.classes import LocalRegistry
with LocalRegistry() as reg:
reg.add(str, lambda: "TEST_OVERRIDE")
value = reg.randomize(str) # -> "TEST_OVERRIDE"
# Global RANDOMIZERS is untouched outside the `with` block
This all works without ever having to pass a registry object around explicitly โ every core function automatically resolves "whichever registry is currently active" behind the scenes.
โก๏ธ Full class-by-class, method-by-method breakdown, plus the singleton and context-state mechanics:
๐ท๏ธ Building Custom Randomizers: value_type_name
When writing your own randomizers โ especially ones that need to know which type hint
they were actually resolved for (containers, unions, or any generic-aware generator) โ
you don't need to pass that information manually through kwargs. The
@value_type_name decorator marks a parameter to receive it automatically.
from simplibs.randomize.tools.decorator import value_type_name
@value_type_name("my_type")
def randomize_my_container(my_type: Any = None, *, min_length: int = 1) -> Any:
...
Once decorated, calling randomize(my_type_hint) automatically injects my_type_hint
into the my_type parameter โ unless you've already supplied it explicitly, in which
case your value always wins.
Under the hood:
def value_type_name(param_name: str) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
"""Decorator marking a function parameter to receive the target value type automatically."""
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
# 1. Input validation
if not isinstance(param_name, str):
raise_param_name_is_not_str(param_name, func)
# 2. Attach parameter metadata attribute
func._value_type_name = param_name
# 3. Return the modified callable
return func
return decorator
This is exactly the mechanism randomize() itself relies on internally for every
built-in type-aware randomizer (randomize_dict, randomize_list, randomize_union,
...) โ see README_MAIN_FUNCTIONS
for the injection logic on the calling side.
โ ๏ธ Exceptions
Every exception raised by simplibs-randomize is built on top of
simplibs.exception.SimpleException โ
meaning failures don't just crash, they explain what went wrong, what was expected, and
how to fix it, instead of a bare traceback.
The library's single base exception is RandomizeError:
from simplibs.exception import SimpleException
class RandomizeError(SimpleException):
"""Base exception class for all errors originating from the SimpleRandom library."""
# Skip internal library frames when generating error location metadata.
# This ensures that error messages point to user code rather than internal
# implementation details, unless no user-level frames remain.
_skip_locations = ("simplibs/random",)
Every error raised internally passes through RandomizeError, so it's always catchable
that way. On top of that, individual call sites can additionally pass a native exception
type (e.g. TypeError, KeyError) via exception=.... SimpleException then
dynamically injects that type into the raised exception's inheritance chain โ so the
same error becomes catchable both as RandomizeError and as the native type you'd
naturally expect:
raise RandomizeError(
error_name="UNSUPPORTED CHOICE TYPES",
label="choices",
value=unknown_types,
problem="The provided choices contain unsupported types for Any.",
expected="Registered types in global scope.",
how_to_fix="Register the type first, e.g. RANDOMIZERS.add(MyType, my_randomizer).",
exception=TypeError,
)
# Catchable both ways:
try:
...
except RandomizeError:
...
except TypeError:
...
If a call site doesn't pass exception=... at all, the error is still fully catchable
via RandomizeError alone.
๐งฉ A Note on Scope
simplibs-randomize deliberately ships with a solid, well-tested core rather than
an exhaustive catalogue of every possible type under the sun. It covers the primitives,
collections, and structural constructs you'll actually reach for day to day โ and the
registry/override system exists precisely so you can extend it with your own
domain-specific randomizers as your needs grow, without ever having to modify the
library itself. Think of it as a skeleton built to be used immediately and built upon.
โฏ๏ธ About simplibs
All libraries in the simplibs (Simple Libraries) ecosystem share a common engineering philosophy:
- Dyslexia-friendly: We actively minimize cognitive load. Code is atomized into small, self-contained units, files are named directly after the logical task they perform, and explanations describe why something is designed, not just what it is.
- Programmer's Zen: Nothing should be missing, and nothing should be superfluous. We value clean execution paths and robust, understandable code architectures over rushed, messy feature sets.
- Defensive Style: We actively anticipate edge cases and failure modes so that only safe operational paths remain. Our code is built to degrade gracefully rather than crash unexpectedly.
- Minimalism: Find the most direct path to the goal in as few operational steps as possible without taking shortcuts on safety, readability, or completeness.
- Code as Craft: Code should be pleasant to look at, readable at a glance, and evoke structural harmony. We treat software engineering as a precision trade.
๐ค Contributing & Community
This is an open-source project built with love and care. We strongly believe in community collaboration and welcome any feedback, bug reports, or feature ideas!
- Want to contribute? Feel free to open an Issue or submit a Pull Request.
- Want to get in touch? If you'd like to discuss the project further, collaborate, or just say hello, feel free to open a GitHub Issue or start a Discussion.
๐ License
This library is released under the MIT License. Build great things!
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file simplibs_randomize-0.1.0.tar.gz.
File metadata
- Download URL: simplibs_randomize-0.1.0.tar.gz
- Upload date:
- Size: 97.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
92d478104c920ed0add9b83ddc9e496c816701b5b2796e02441fd99564d7dcff
|
|
| MD5 |
6e7b9fd941ff296899846cb4ef4ff71c
|
|
| BLAKE2b-256 |
1c99392616a11df4d20b0510ea5ec60152c7db4b024e55972c38fc5815bea8db
|
File details
Details for the file simplibs_randomize-0.1.0-py3-none-any.whl.
File metadata
- Download URL: simplibs_randomize-0.1.0-py3-none-any.whl
- Upload date:
- Size: 193.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7d829aa57271f2ae5a146c3fd2fd5a37c4c6004271fb58b5e1fa2c79f36f2e88
|
|
| MD5 |
54bda8abfe81e1a03e86cafc7e257ff3
|
|
| BLAKE2b-256 |
12b8ebcae3fe1ec505239414017c651269f91c148b6c585d8fbf2450451f4a7a
|