Source code for libb.rand

import logging
import os
import random
from functools import wraps

logger = logging.getLogger(__name__)

__all__ = [
    'random_choice',
    'random_int',
    'random_sample',
    'random_random',
]


def rseed(func):
    """Decorator to seed random with OS entropy before function call.

    :param func: Function to wrap.
    :returns: Wrapped function with OS-seeded randomness.
    """
    @wraps(func)
    def wrapper(*args, **kwargs):
        RAND_SIZE = 4
        random_data = os.urandom(RAND_SIZE)
        random_seed = int.from_bytes(random_data, byteorder='big')
        random.seed(random_seed)
        return func(*args, **kwargs)
    return wrapper


[docs] @rseed def random_choice(choices: list): """Random choice from a list, seeded with OS entropy. :param list choices: List of items to choose from. :returns: Randomly selected item. Example:: >>> result = random_choice(['a', 'b', 'c']) >>> result in ['a', 'b', 'c'] True """ choices = list(choices) # copy to avoid mutating input random.shuffle(choices) return choices[0]
[docs] @rseed def random_int(a: int, b: int): """Random integer between a and b inclusive, seeded with OS entropy. :param int a: Lower bound. :param int b: Upper bound. :returns: Random integer in [a, b]. :rtype: int Example:: >>> result = random_int(1, 10) >>> 1 <= result <= 10 True """ return random.randint(a, b)
[docs] @rseed def random_random(): """Random float in [0, 1), seeded with OS entropy. :returns: Random float. :rtype: float Example:: >>> result = random_random() >>> 0 <= result < 1 True """ return random.random()
[docs] @rseed def random_sample(arr, size: int = 1): """Random sample of N elements from numpy array. :param np.array arr: Array to sample from. :param int size: Number of elements to sample. :returns: Array of sampled elements. :rtype: np.array """ import numpy as np return arr[np.random.choice(len(arr), size=size, replace=False)]