Skip to main content

๐ŸŽฒ simplibs-randomize

PyPI Python Licence

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 global RANDOMIZERS singleton, also usable as a fully standalone registry.
    โžก๏ธ README_RANDOMIZERS_REGISTRY

  • LocalRegistry โ€” isolated, scoped overrides with transparent global fallback.
    โžก๏ธ README_LOCAL_REGISTRY

  • The RANDOMIZERS singleton & 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 = 5
max_length: int = 15
randomize_decimal min_value: float = 0.0
max_value: float = 1000.0
exponent: int = -2
randomize_float min_value: float = 0.0
max_value: float = 1000.0
ndigits: int = 2
randomize_int min_value: int = 0
max_value: int = 1000
randomize_str min_length: int = 5
max_length: int = 15
alphabet: 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 = 0
max_hour: int = 23
randomize_timedelta min_seconds: int = 0
max_seconds: int = 2592000 (30 days)

2. Type-Aware Randomizers

2.1 Collections

- - - - - Randomizer - - - - - - - - - - - - - - - Parameters (default) - - - - - - - - - -
randomize_dict dict_type: Any = dict
min_length: int = 1
max_length: int = 5
randomize_list list_type: Any = list
min_length: int = 1
max_length: int = 5
randomize_set set_type: Any = set[str]
min_length: int = 1
max_length: int = 5
max_attempts: int = 50
randomize_tuple tuple_type: Any = tuple
min_length: int = 1
max_length: int = 5

2.2 Structural

- - - - - Randomizer - - - - - - - - - - - - - - - Parameters (default) - - - - - - - - - -
randomize_enum enum_type: type[Enum] = Enum
exclude: Iterable[Enum] | None = None
randomize_literal literal_type: Any = Literal
randomize_union union_type: Any = UnionType
none_probability: float = 0.3

3. Meta Types

- - - - - Randomizer - - - - - - - - - - - - - - - Parameters (default) - - - - - - - - - -
randomize_any *choices: Any
validate: 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!


โ–ฒ Back to Top

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

simplibs_randomize-0.1.0.tar.gz (97.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

simplibs_randomize-0.1.0-py3-none-any.whl (193.7 kB view details)

Uploaded Python 3

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

Hashes for simplibs_randomize-0.1.0.tar.gz
Algorithm Hash digest
SHA256 92d478104c920ed0add9b83ddc9e496c816701b5b2796e02441fd99564d7dcff
MD5 6e7b9fd941ff296899846cb4ef4ff71c
BLAKE2b-256 1c99392616a11df4d20b0510ea5ec60152c7db4b024e55972c38fc5815bea8db

See more details on using hashes here.

File details

Details for the file simplibs_randomize-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for simplibs_randomize-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7d829aa57271f2ae5a146c3fd2fd5a37c4c6004271fb58b5e1fa2c79f36f2e88
MD5 54bda8abfe81e1a03e86cafc7e257ff3
BLAKE2b-256 12b8ebcae3fe1ec505239414017c651269f91c148b6c585d8fbf2450451f4a7a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page