bases.random API documentation
Description: Functions to generate random data …

# Module `bases.random`

Functions to generate random data.

The main functions are `rand_bytes()` and `rand_str()`:

- the function call `rand_bytes()(n)` returns an iterator yielding a stream of `n` random bytestrings
- the function call `rand_bytes(n, encoding=enc)` returns an iterator yielding a stream of `n` random bytestrings valid for the encoding (i.e. they should be encoded without error)
- the function call `rand_str(n, encoding=enc)` returns an iterator yielding a stream of `n` random strings valid for the encoding (i.e. they should be decoded without error)
- the function call `rand_str(n, alphabet=alph)` returns an iterator yielding a stream of `n` random strings with characters from the alphabet
- the function call `rand_bytes()` returns an iterator yielding an infinite stream of random bytestrings
- the function call `rand_bytes(encoding=enc)` returns an iterator yielding an infinite stream of random bytestrings valid for the encoding
- the function call `rand_str(encoding=enc)` returns an iterator yielding an infinite stream of random strings valid for the encoding
- the function call `rand_str(alphabet=alph)` returns an iterator yielding an infinite stream of random strings with characters from the alphabet

Example usage:

        >>> from bases import base10, base32
        >>> from bases import random
        >>> my_random_bytes = list(random.rand_bytes(4, encoding=base10))
        >>> [list(b) for b in my_random_bytes]
        [[0, 30, 135, 156, 223, 90, 134, 83, 6, 243, 245],
         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 216, 87, 1, 2],
         [70, 98, 190, 187, 66, 224, 178],
         [0, 96, 63]]
        >>> my_random_strings = list(random.rand_str(4, encoding=base32))
        >>> my_random_strings
        ['2CQ7ZT6WNI', 'IGQJTGA', 'V6GW3UN64QDAFZA7', 'PUEMOPJ4']

The `options()` context manager is used to set options temporarily, within the scope of a `with` directive:

- `min_bytes` and `max_bytes` bound the length of bytestrings yielded by `rand_bytes()`
- `min_chars` and `max_chars` bound the length of strings yielded by `rand_str()`

Options can be set with `set_options()` and reset with `reset_options()`. A read-only view on options can be obtained from `get_options()`, and a read-only view on default options can be obtained from `default_options()`:

        >>> random.default_options()
        mappingproxy({'min_bytes': 0, 'max_bytes': 16,
                      'min_chars': 0, 'max_chars': 16})

Expand source code

    """
        Functions to generate random data.

        The main functions are `rand_bytes` and `rand_str`:

        - the function call `rand_bytes(n)` returns an iterator yielding a stream of `n` random bytestrings
        - the function call `rand_bytes(n, encoding=enc)` returns an iterator yielding a stream of `n` random bytestrings valid for the encoding
          (i.e. they should be encoded without error)
        - the function call `rand_str(n, encoding=enc)` returns an iterator yielding a stream of `n` random strings valid for the encoding
          (i.e. they should be decoded without error)
        - the function call `rand_str(n, alphabet=alph)` returns an iterator yielding a stream of `n` random strings with characters from the alphabet
        - the function call `rand_bytes()` returns an iterator yielding an infinite stream of random bytestrings
        - the function call `rand_bytes(encoding=enc)` returns an iterator yielding an infinite stream of random bytestrings valid for the encoding
        - the function call `rand_str(encoding=enc)` returns an iterator yielding an infinite stream of random strings valid for the encoding
        - the function call `rand_str(alphabet=alph)` returns an iterator yielding an infinite stream of random strings with characters from the alphabet

        Example usage:

        ```python
            >>> from bases import base10, base32
            >>> from bases import random
            >>> my_random_bytes = list(random.rand_bytes(4, encoding=base10))
            >>> [list(b) for b in my_random_bytes]
            [[0, 30, 135, 156, 223, 90, 134, 83, 6, 243, 245],
             [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 216, 87, 1, 2],
             [70, 98, 190, 187, 66, 224, 178],
             [0, 96, 63]]
            >>> my_random_strings = list(random.rand_str(4, encoding=base32))
            >>> my_random_strings
            ['2CQ7ZT6WNI', 'IGQJTGA', 'V6GW3UN64QDAFZA7', 'PUEMOPJ4']
        ```

        The `options()` context manager is used to set options temporarily, within the scope of a `with` directive:

        - `min_bytes` and `max_bytes` bound the length of bytestrings yielded by `rand_bytes`
        - `min_chars` and `max_chars` bound the length of strings yielded by `rand_str`

        Options can be set with `set_options()` and reset with `reset_options()`. A read-only view on options can be obtained
        from `get_options()`, and a read-only view on default options can be obtained from `default_options()`:

        ```py
            >>> random.default_options()
            mappingproxy({'min_bytes': 0, 'max_bytes': 16,
                          'min_chars': 0, 'max_chars': 16})
        ```
    """

    # pylint: disable = global-statement

    from contextlib import contextmanager
    from itertools import chain, islice
    from random import Random # pylint: disable = import-self
    from types import MappingProxyType
    from typing import Any, Dict, Iterator, Mapping, Optional

    from .alphabet import Alphabet
    from .encoding import BaseEncoding, SimpleBaseEncoding, ZeropadBaseEncoding, BlockBaseEncoding, FixcharBaseEncoding

    _default_options: Mapping[str, Any] = MappingProxyType({
        "min_bytes": 0,
        "max_bytes": 16,
        "min_chars": 0,
        "max_chars": 16,
    })

    _options: Mapping[str, Any] = MappingProxyType(_default_options)
    _rand: Random = Random(0)

    def reset_options() -> None:
        """
            Resets random generation options to their default values.
        """
        global _options
        global _rand
        _options = _default_options
        _rand = Random(0)

    def default_options() -> Mapping[str, Any]:
        """
            Readonly view of the default random generation options.
        """
        return _default_options

    def get_options() -> Mapping[str, Any]:
        """
            Readonly view of the current random generation options.
        """
        return _options

    @contextmanager
    def options(*,
                seed: Optional[int] = None,
                min_bytes: Optional[int] = None,
                max_bytes: Optional[int] = None,
                min_chars: Optional[int] = None,
                max_chars: Optional[int] = None,) -> Iterator[None]:
        """
            Returns with-statement context manager for temporary option setting:

            ```py
                with options(**options):
                    for value in rand_data(num_samples, encoding):
                        ...
            ```

            See `set_options` for a description of the options.
        """
        # pylint: disable = too-many-locals
        global _options
        global _rand
        try:
            _old_options = _options
            _old_rand = _rand
            set_options(seed=seed,
                        min_bytes=min_bytes, max_bytes=max_bytes,
                        min_chars=min_chars, max_chars=max_chars,)
            yield
        finally:
            _options = _old_options
            _rand = _old_rand

    def set_options(*,
                    seed: Optional[int] = None,
                    min_bytes: Optional[int] = None,
                    max_bytes: Optional[int] = None,
                    min_chars: Optional[int] = None,
                    max_chars: Optional[int] = None,) -> None:
        """
            Permanently sets random generation options:

            ```python
                seed: int           # set new random number generator, with this seed
                min_bytes: int      # min length of `bytes` value
                max_bytes: int      # max length of `bytes` value
                min_chars: int      # min length of `str` value
                max_chars: int      # max length of `str` value
            ```

        """
        # pylint: disable = too-many-branches, too-many-locals, too-many-statements
        global _options
        global _rand
        # set newly passed options
        _new_options: Dict[str, Any] = {}
        if seed is not None:
            _rand = Random(seed)
        if min_bytes is not None:
            if min_bytes < 0:
                raise ValueError("Value for min_bytes is negative.")
            _new_options["min_bytes"] = min_bytes
        if max_bytes is not None:
            if max_bytes < 0:
                raise ValueError("Value for max_bytes is negative.")
            _new_options["max_bytes"] = max_bytes
        if min_chars is not None:
            if min_chars < 0:
                raise ValueError("Value for min_chars is negative.")
            _new_options["min_chars"] = min_chars
        if max_chars is not None:
            if max_chars < 0:
                raise ValueError("Value for max_chars is negative.")
            _new_options["max_chars"] = max_chars
        # pass-through other options with former values
        for k, v in _options.items():
            if k not in _new_options:
                _new_options[k] = v
        # check compatibility conditions
        if _new_options["min_bytes"] > _new_options["max_bytes"]:
            raise ValueError("Value for min_bytes is larger than value for max_bytes.")
        if _new_options["min_chars"] > _new_options["max_chars"]:
            raise ValueError("Value for min_chars is larger than value for max_chars.")
        # update options
        _options = MappingProxyType(_new_options)

    def rand_bytes(n: Optional[int] = None, *, encoding: Optional[BaseEncoding] = None) -> Iterator[bytes]:
        """
            Generates a stream of random `bytes` objects.
            If a number `n` is given, that number of samples is yelded.
            If an encoding `encoding` is given, only bytes valid for that encoding are yielded.

            Example usage:

            ```py
            >>> my_random_bytes = list(random.rand_bytes(4, encoding=base10))
            >>> [list(b) for b in my_random_bytes]
            [[0, 30, 135, 156, 223, 90, 134, 83, 6, 243, 245],
             [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 216, 87, 1, 2],
             [70, 98, 190, 187, 66, 224, 178],
             [0, 96, 63]]
            ```
        """
        if encoding is None:
            return rand_raw_bytes(n)
        if isinstance(encoding, SimpleBaseEncoding):
            return _rand_bytes_simple_enc(n, encoding)
        if isinstance(encoding, ZeropadBaseEncoding):
            return _rand_bytes_zeropad_enc(n, encoding)
        if isinstance(encoding, BlockBaseEncoding):
            return _rand_bytes_block_enc(n, encoding)
        if isinstance(encoding, FixcharBaseEncoding):
            return _rand_bytes_fixedchar_enc(n, encoding)
        raise ValueError(f"Unsupported encoding type {type(encoding)}")

    def rand_raw_bytes(n: Optional[int] = None, *, min_bytes: Optional[int] = None, max_bytes: Optional[int] = None) -> Iterator[bytes]:
        """
            Generates a stream of random `bytes` objects.
            If a number `n` is given, that number of samples is yelded.
            The optional `min_bytes` and `max_bytes` parameters can be used to set a minimum/maximum length
            for the `bytes` objects: if `None`, the values are fetched from `get_options`.
        """
        if n is not None and n < 0:
            raise ValueError()
        if min_bytes is None:
            min_bytes = _options["min_bytes"]
        if max_bytes is None:
            max_bytes = _options["max_bytes"]
        rand = _rand
        # main yielding loop
        yielded = 0
        while n is None or yielded < n:
            # sample random length
            l = rand.randint(min_bytes, max_bytes)
            # yield random unsigned integer filling l bytes
            i = rand.randrange(0, 256**l)
            yield i.to_bytes(l, byteorder="big")
            yielded += 1

    def _rand_bytes_simple_enc(n: Optional[int], _: SimpleBaseEncoding) -> Iterator[bytes]:
        if n is not None and n < 0:
            raise ValueError()
        min_bytes = _options["min_bytes"]
        max_bytes = _options["max_bytes"]
        rand = _rand
        # main yielding loop
        yielded = 0
        while n is None or yielded < n:
            # sample random length
            l = rand.randint(min_bytes, max_bytes)
            # yield random unsigned integer filling l bytes with no leading zero bytes
            if l == 0:
                i = 0
            else:
                i = rand.randrange(256**(l-1), 256**l)
            yield i.to_bytes(l, byteorder="big")
            yielded += 1

    def _rand_bytes_zeropad_enc(n: Optional[int], _: ZeropadBaseEncoding) -> Iterator[bytes]:
        if n is not None and n < 0:
            raise ValueError()
        min_bytes = _options["min_bytes"]
        max_bytes = _options["max_bytes"]
        rand = _rand
        # main yielding loop
        yielded = 0
        while n is None or yielded < n:
            # sample random length
            l = rand.randint(min_bytes, max_bytes)
            # sample random number of leading zero bytes
            z = rand.randint(0, l)
            # yield random unsigned integer filling l-z bytes
            if l == z:
                i = 0
            else:
                i = rand.randrange(256**(l-z-1), 256**(l-z))
            yield i.to_bytes(l, byteorder="big")
            yielded += 1

    def _rand_bytes_block_enc(n: Optional[int], encoding: BlockBaseEncoding) -> Iterator[bytes]:
        if n is not None and n < 0:
            raise ValueError()
        min_bytes = _options["min_bytes"]
        max_bytes = _options["max_bytes"]
        rand = _rand
        # pre-compute valid bytestring lengths for block base encoding
        block_nbytes = encoding.block_nbytes
        nbytes2nchars = encoding.nbytes2nchars
        valid_lengths = [l for l in range(min_bytes, max_bytes+1)
                         if l%block_nbytes == 0 or l%block_nbytes in nbytes2nchars]
        # main yielding loop
        yielded = 0
        while n is None or yielded < n:
            # sample random valid length
            l = rand.choice(valid_lengths)
            # yield random unsigned integer filling l bytes
            i = rand.randrange(0, 256**l)
            yield i.to_bytes(l, byteorder="big")
            yielded += 1

    def _rand_bytes_fixedchar_enc(n: Optional[int], _: FixcharBaseEncoding) -> Iterator[bytes]:
        return rand_raw_bytes(n)

    def rand_str(n: Optional[int] = None, *, encoding: Optional[BaseEncoding]=None, alphabet: Optional[Alphabet]=None) -> Iterator[str]:
        """
            Generates a stream of random strings.
            If a number `n` is given, that number of samples is yelded.
            Exactly one of `encoding` or `alphabet` must be given:
            - if an `encoding` is given, only strings valid for that encoding are yielded
            - if an `alphabet` is given, only strings valid for that alphabet are yielded

            Example usage:

            ```py
            >>> my_random_strings = list(random.rand_str(4, encoding=base32))
            >>> my_random_strings
            ['2CQ7ZT6WNI', 'IGQJTGA', 'V6GW3UN64QDAFZA7', 'PUEMOPJ4']
            ```

        """
        if encoding is None:
            if alphabet is None:
                raise ValueError("One of 'encoding' or 'alphabet' must be specified.")
            return _rand_alphabet_string(n, alphabet)
        if alphabet is not None:
            raise ValueError("Exactly one of 'encoding' or 'alphabet' must be specified.")
        if isinstance(encoding, SimpleBaseEncoding):
            return _rand_str_simple_enc(n, encoding)
        if isinstance(encoding, ZeropadBaseEncoding):
            return _rand_str_zeropad_enc(n, encoding)
        if isinstance(encoding, BlockBaseEncoding):
            return _rand_str_block_enc(n, encoding)
        if isinstance(encoding, FixcharBaseEncoding):
            return _rand_str_fixedchar_enc(n, encoding)
        raise ValueError(f"Unsupported encoding type {type(encoding)}")

    def rand_char(n: Optional[int] = None, *, alphabet: Alphabet, non_zero: bool = False) -> Iterator[str]:
        """
            Generates a stream of random characters from the alphabet (one character yielded at a time).
            If a number `n` is given, that number of samples is yelded.
            If `non_zero` is `True`, the zero character for the alphabet is not yielded.
        """
        if n is not None and n < 0:
            raise ValueError()
        start = 1 if non_zero else 0
        end = len(alphabet)
        rand = _rand
        yielded = 0
        while n is None or yielded < n:
            # yield random character (excluding zero character, if non_zero is True)
            idx = rand.randrange(start, end)
            yield alphabet[idx]
            yielded += 1

    def _rand_alphabet_string(n: Optional[int], alphabet: Alphabet) -> Iterator[str]:
        if n is not None and n < 0:
            raise ValueError()
        min_chars = _options["min_chars"]
        max_chars = _options["max_chars"]
        rand = _rand
        # infinte random character stream
        rand_char_stream = rand_char(alphabet=alphabet)
        # main yielding loop
        yielded = 0
        while n is None or yielded < n:
            # sample random length
            l = rand.randint(min_chars, max_chars)
            # yield random string filling l characters
            yield "".join(islice(rand_char_stream, l))
            yielded += 1

    def _rand_str_simple_enc(n: Optional[int], encoding: SimpleBaseEncoding) -> Iterator[str]:
        if n is not None and n < 0:
            raise ValueError()
        min_chars = _options["min_chars"]
        max_chars = _options["max_chars"]
        rand = _rand
        # infinte random character streams
        rand_char_stream = rand_char(alphabet=encoding.alphabet)
        rand_nonzero_char_stream = rand_char(alphabet=encoding.alphabet, non_zero=True)
        # main yielding loop
        yielded = 0
        while n is None or yielded < n:
            # sample random length
            l = rand.randint(min_chars, max_chars)
            # yield random str filling l characters with no leading zero characters
            if l == 0:
                yield ""
            else:
                yield "".join(chain(islice(rand_nonzero_char_stream, 1),
                                    islice(rand_char_stream, l-1)))
            yielded += 1

    def _rand_str_zeropad_enc(n: Optional[int], encoding: ZeropadBaseEncoding) -> Iterator[str]:
        if n is not None and n < 0:
            raise ValueError()
        min_chars = _options["min_chars"]
        max_chars = _options["max_chars"]
        rand = _rand
        # zero character
        zero_char = encoding.zero_char
        # infinte random character streams
        rand_char_stream = rand_char(alphabet=encoding.alphabet)
        rand_nonzero_char_stream = rand_char(alphabet=encoding.alphabet, non_zero=True)
        # main yielding loop
        yielded = 0
        while n is None or yielded < n:
            # sample random length
            l = rand.randint(min_chars, max_chars)
            # sample random number of leading zero chars
            z = rand.randint(0, l)
            # yield random str filling l characters with given number of leading zeros
            if l-z == 0:
                yield zero_char*z
            else:
                yield zero_char*z+"".join(chain(islice(rand_nonzero_char_stream, 1),
                                                islice(rand_char_stream, l-z-1)))
            yielded += 1

    def rand_block_chars(n: Optional[int] = None, *, block_nchars: int, encoding: BlockBaseEncoding) -> Iterator[str]:
        """
            Generates a stream of random char blocks for a block base encoding.
            If a number `n` is given, that number of samples is yelded.
            The number `block_nchars` of characters in the blocks must be valid for the encoding.
        """
        if n is not None and n < 0:
            raise ValueError()
        # extract block size in chars and bytes
        nchars2nbytes = encoding.nchars2nbytes
        if block_nchars not in nchars2nbytes:
            raise ValueError(f"Invalid number of characters per block ({block_nchars})")
        block_nbytes = nchars2nbytes[block_nchars]
        # infinite random byte stream
        rand_bytes_stream = rand_raw_bytes(min_bytes=1, max_bytes=1)
        # main yielding loop
        yielded = 0
        while n is None or yielded < n:
            block_bytes = b"".join(islice(rand_bytes_stream, block_nbytes))
            s = encoding.encode(block_bytes)
            yield s
            yielded += 1

    def _rand_str_block_enc(n: Optional[int], encoding: BlockBaseEncoding) -> Iterator[str]:
        if n is not None and n < 0:
            raise ValueError()
        min_chars = _options["min_chars"]
        max_chars = _options["max_chars"]
        rand = _rand
        # pre-compute valid string lengths for block base encoding
        block_nchars = encoding.block_nchars
        nchars2nbytes = encoding.nchars2nbytes
        valid_lengths = [l for l in range(min_chars, max_chars+1)
                         if l%block_nchars == 0 or l%block_nchars in nchars2nbytes]
        # infinte random character streams
        rand_block_stream = {
            nchars: rand_block_chars(block_nchars=nchars, encoding=encoding)
            for nchars in nchars2nbytes
        }
        # main yielding loop
        yielded = 0
        while n is None or yielded < n:
            # sample random valid length
            l = rand.choice(valid_lengths)
            num_full_blocks, final_block_nchars = divmod(l, block_nchars)
            full_blocks = islice(rand_block_stream[block_nchars], num_full_blocks)
            if final_block_nchars == 0:
                yield "".join(full_blocks)
            else:
                final_block = islice(rand_block_stream[final_block_nchars], 1)
                yield "".join(chain(full_blocks, final_block))
            yielded += 1

    def _rand_str_fixedchar_enc(n: Optional[int], encoding: FixcharBaseEncoding) -> Iterator[str]:
        # pylint: disable = too-many-locals
        if n is not None and n < 0:
            raise ValueError()
        min_chars = _options["min_chars"]
        max_chars = _options["max_chars"]
        rand = _rand
        # pre-compute valid string lengths for fixed-char base encoding
        alphabet = encoding.alphabet
        char_nbits = encoding.char_nbits
        valid_lengths = [l for l in range(min_chars, max_chars+1)
                         if (l*char_nbits)%8 < char_nbits]
        # infinte random character stream
        rand_char_stream = rand_char(alphabet=encoding.alphabet)
        # main yielding loop
        yielded = 0
        while n is None or yielded < n:
            # sample random length
            l = rand.choice(valid_lengths)
            # yield random str filling l characters with pad bits set to zero
            extra_nbits = (l*char_nbits)%8
            if extra_nbits == 0:
                s = "".join(islice(rand_char_stream, l))
            else:
                all_chars_but_last = "".join(islice(rand_char_stream, l-1))
                last_char_idx = rand.randrange(0, 2**(char_nbits-extra_nbits))<<extra_nbits
                last_char = alphabet[last_char_idx]
                s = all_chars_but_last+last_char
            if encoding.padding == "ignore":
                yield s
            else:
                yield encoding.pad_string(s)
            yielded += 1

## Functions

`def default_options() ‑> Mapping[str, Any]`

  Readonly view of the default random generation options.

  Expand source code

      def default_options() -> Mapping[str, Any]:
          """
              Readonly view of the default random generation options.
          """
          return _default_options

`def get_options() ‑> Mapping[str, Any]`

  Readonly view of the current random generation options.

  Expand source code

      def get_options() -> Mapping[str, Any]:
          """
              Readonly view of the current random generation options.
          """
          return _options

`def options(*, seed: Optional[int] = None, min_bytes: Optional[int] = None, max_bytes: Optional[int] = None, min_chars: Optional[int] = None, max_chars: Optional[int] = None) ‑> Iterator[None]`

  Returns with-statement context manager for temporary option setting:

          with options(**options):
              for value in rand_data(num_samples, encoding):
                  ...

  See `set_options()` for a description of the options.

  Expand source code

      @contextmanager
      def options(*,
                  seed: Optional[int] = None,
                  min_bytes: Optional[int] = None,
                  max_bytes: Optional[int] = None,
                  min_chars: Optional[int] = None,
                  max_chars: Optional[int] = None,) -> Iterator[None]:
          """
              Returns with-statement context manager for temporary option setting:

              ```py
                  with options(**options):
                      for value in rand_data(num_samples, encoding):
                          ...
              ```

              See `set_options` for a description of the options.
          """
          # pylint: disable = too-many-locals
          global _options
          global _rand
          try:
              _old_options = _options
              _old_rand = _rand
              set_options(seed=seed,
                          min_bytes=min_bytes, max_bytes=max_bytes,
                          min_chars=min_chars, max_chars=max_chars,)
              yield
          finally:
              _options = _old_options
              _rand = _old_rand

`def rand_block_chars(n: Optional[int] = None, *, block_nchars: int, encoding: BlockBaseEncoding) ‑> Iterator[str]`

  Generates a stream of random char blocks for a block base encoding. If a number `n` is given, that number of samples is yelded. The number `block_nchars` of characters in the blocks must be valid for the encoding.

  Expand source code

      def rand_block_chars(n: Optional[int] = None, *, block_nchars: int, encoding: BlockBaseEncoding) -> Iterator[str]:
          """
              Generates a stream of random char blocks for a block base encoding.
              If a number `n` is given, that number of samples is yelded.
              The number `block_nchars` of characters in the blocks must be valid for the encoding.
          """
          if n is not None and n < 0:
              raise ValueError()
          # extract block size in chars and bytes
          nchars2nbytes = encoding.nchars2nbytes
          if block_nchars not in nchars2nbytes:
              raise ValueError(f"Invalid number of characters per block ({block_nchars})")
          block_nbytes = nchars2nbytes[block_nchars]
          # infinite random byte stream
          rand_bytes_stream = rand_raw_bytes(min_bytes=1, max_bytes=1)
          # main yielding loop
          yielded = 0
          while n is None or yielded < n:
              block_bytes = b"".join(islice(rand_bytes_stream, block_nbytes))
              s = encoding.encode(block_bytes)
              yield s
              yielded += 1

`def rand_bytes(n: Optional[int] = None, *, encoding: Optional[BaseEncoding] = None) ‑> Iterator[bytes]`

  Generates a stream of random `bytes` objects. If a number `n` is given, that number of samples is yelded. If an encoding `encoding` is given, only bytes valid for that encoding are yielded.

  Example usage:

      >>> my_random_bytes = list(random.rand_bytes(4, encoding=base10))
      >>> [list(b) for b in my_random_bytes]
      [[0, 30, 135, 156, 223, 90, 134, 83, 6, 243, 245],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 216, 87, 1, 2],
       [70, 98, 190, 187, 66, 224, 178],
       [0, 96, 63]]

  Expand source code

      def rand_bytes(n: Optional[int] = None, *, encoding: Optional[BaseEncoding] = None) -> Iterator[bytes]:
          """
              Generates a stream of random `bytes` objects.
              If a number `n` is given, that number of samples is yelded.
              If an encoding `encoding` is given, only bytes valid for that encoding are yielded.

              Example usage:

              ```py
              >>> my_random_bytes = list(random.rand_bytes(4, encoding=base10))
              >>> [list(b) for b in my_random_bytes]
              [[0, 30, 135, 156, 223, 90, 134, 83, 6, 243, 245],
               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 216, 87, 1, 2],
               [70, 98, 190, 187, 66, 224, 178],
               [0, 96, 63]]
              ```
          """
          if encoding is None:
              return rand_raw_bytes(n)
          if isinstance(encoding, SimpleBaseEncoding):
              return _rand_bytes_simple_enc(n, encoding)
          if isinstance(encoding, ZeropadBaseEncoding):
              return _rand_bytes_zeropad_enc(n, encoding)
          if isinstance(encoding, BlockBaseEncoding):
              return _rand_bytes_block_enc(n, encoding)
          if isinstance(encoding, FixcharBaseEncoding):
              return _rand_bytes_fixedchar_enc(n, encoding)
          raise ValueError(f"Unsupported encoding type {type(encoding)}")

`def rand_char(n: Optional[int] = None, *, alphabet: Alphabet, non_zero: bool = False) ‑> Iterator[str]`

  Generates a stream of random characters from the alphabet (one character yielded at a time). If a number `n` is given, that number of samples is yelded. If `non_zero` is `True`, the zero character for the alphabet is not yielded.

  Expand source code

      def rand_char(n: Optional[int] = None, *, alphabet: Alphabet, non_zero: bool = False) -> Iterator[str]:
          """
              Generates a stream of random characters from the alphabet (one character yielded at a time).
              If a number `n` is given, that number of samples is yelded.
              If `non_zero` is `True`, the zero character for the alphabet is not yielded.
          """
          if n is not None and n < 0:
              raise ValueError()
          start = 1 if non_zero else 0
          end = len(alphabet)
          rand = _rand
          yielded = 0
          while n is None or yielded < n:
              # yield random character (excluding zero character, if non_zero is True)
              idx = rand.randrange(start, end)
              yield alphabet[idx]
              yielded += 1

`def rand_raw_bytes(n: Optional[int] = None, *, min_bytes: Optional[int] = None, max_bytes: Optional[int] = None) ‑> Iterator[bytes]`

  Generates a stream of random `bytes` objects. If a number `n` is given, that number of samples is yelded. The optional `min_bytes` and `max_bytes` parameters can be used to set a minimum/maximum length for the `bytes` objects: if `None`, the values are fetched from `get_options()`.

  Expand source code

      def rand_raw_bytes(n: Optional[int] = None, *, min_bytes: Optional[int] = None, max_bytes: Optional[int] = None) -> Iterator[bytes]:
          """
              Generates a stream of random `bytes` objects.
              If a number `n` is given, that number of samples is yelded.
              The optional `min_bytes` and `max_bytes` parameters can be used to set a minimum/maximum length
              for the `bytes` objects: if `None`, the values are fetched from `get_options`.
          """
          if n is not None and n < 0:
              raise ValueError()
          if min_bytes is None:
              min_bytes = _options["min_bytes"]
          if max_bytes is None:
              max_bytes = _options["max_bytes"]
          rand = _rand
          # main yielding loop
          yielded = 0
          while n is None or yielded < n:
              # sample random length
              l = rand.randint(min_bytes, max_bytes)
              # yield random unsigned integer filling l bytes
              i = rand.randrange(0, 256**l)
              yield i.to_bytes(l, byteorder="big")
              yielded += 1

`def rand_str(n: Optional[int] = None, *, encoding: Optional[BaseEncoding] = None, alphabet: Optional[Alphabet] = None) ‑> Iterator[str]`

  Generates a stream of random strings. If a number `n` is given, that number of samples is yelded. Exactly one of `encoding` or `alphabet` must be given: - if an `encoding` is given, only strings valid for that encoding are yielded - if an `alphabet` is given, only strings valid for that alphabet are yielded

  Example usage:

      >>> my_random_strings = list(random.rand_str(4, encoding=base32))
      >>> my_random_strings
      ['2CQ7ZT6WNI', 'IGQJTGA', 'V6GW3UN64QDAFZA7', 'PUEMOPJ4']

  Expand source code

      def rand_str(n: Optional[int] = None, *, encoding: Optional[BaseEncoding]=None, alphabet: Optional[Alphabet]=None) -> Iterator[str]:
          """
              Generates a stream of random strings.
              If a number `n` is given, that number of samples is yelded.
              Exactly one of `encoding` or `alphabet` must be given:
              - if an `encoding` is given, only strings valid for that encoding are yielded
              - if an `alphabet` is given, only strings valid for that alphabet are yielded

              Example usage:

              ```py
              >>> my_random_strings = list(random.rand_str(4, encoding=base32))
              >>> my_random_strings
              ['2CQ7ZT6WNI', 'IGQJTGA', 'V6GW3UN64QDAFZA7', 'PUEMOPJ4']
              ```

          """
          if encoding is None:
              if alphabet is None:
                  raise ValueError("One of 'encoding' or 'alphabet' must be specified.")
              return _rand_alphabet_string(n, alphabet)
          if alphabet is not None:
              raise ValueError("Exactly one of 'encoding' or 'alphabet' must be specified.")
          if isinstance(encoding, SimpleBaseEncoding):
              return _rand_str_simple_enc(n, encoding)
          if isinstance(encoding, ZeropadBaseEncoding):
              return _rand_str_zeropad_enc(n, encoding)
          if isinstance(encoding, BlockBaseEncoding):
              return _rand_str_block_enc(n, encoding)
          if isinstance(encoding, FixcharBaseEncoding):
              return _rand_str_fixedchar_enc(n, encoding)
          raise ValueError(f"Unsupported encoding type {type(encoding)}")

`def reset_options() ‑> None`

  Resets random generation options to their default values.

  Expand source code

      def reset_options() -> None:
          """
              Resets random generation options to their default values.
          """
          global _options
          global _rand
          _options = _default_options
          _rand = Random(0)

`def set_options(*, seed: Optional[int] = None, min_bytes: Optional[int] = None, max_bytes: Optional[int] = None, min_chars: Optional[int] = None, max_chars: Optional[int] = None) ‑> None`

  Permanently sets random generation options:

          seed: int           # set new random number generator, with this seed
          min_bytes: int      # min length of `bytes` value
          max_bytes: int      # max length of `bytes` value
          min_chars: int      # min length of `str` value
          max_chars: int      # max length of `str` value

  Expand source code

      def set_options(*,
                      seed: Optional[int] = None,
                      min_bytes: Optional[int] = None,
                      max_bytes: Optional[int] = None,
                      min_chars: Optional[int] = None,
                      max_chars: Optional[int] = None,) -> None:
          """
              Permanently sets random generation options:

              ```python
                  seed: int           # set new random number generator, with this seed
                  min_bytes: int      # min length of `bytes` value
                  max_bytes: int      # max length of `bytes` value
                  min_chars: int      # min length of `str` value
                  max_chars: int      # max length of `str` value
              ```

          """
          # pylint: disable = too-many-branches, too-many-locals, too-many-statements
          global _options
          global _rand
          # set newly passed options
          _new_options: Dict[str, Any] = {}
          if seed is not None:
              _rand = Random(seed)
          if min_bytes is not None:
              if min_bytes < 0:
                  raise ValueError("Value for min_bytes is negative.")
              _new_options["min_bytes"] = min_bytes
          if max_bytes is not None:
              if max_bytes < 0:
                  raise ValueError("Value for max_bytes is negative.")
              _new_options["max_bytes"] = max_bytes
          if min_chars is not None:
              if min_chars < 0:
                  raise ValueError("Value for min_chars is negative.")
              _new_options["min_chars"] = min_chars
          if max_chars is not None:
              if max_chars < 0:
                  raise ValueError("Value for max_chars is negative.")
              _new_options["max_chars"] = max_chars
          # pass-through other options with former values
          for k, v in _options.items():
              if k not in _new_options:
                  _new_options[k] = v
          # check compatibility conditions
          if _new_options["min_bytes"] > _new_options["max_bytes"]:
              raise ValueError("Value for min_bytes is larger than value for max_bytes.")
          if _new_options["min_chars"] > _new_options["max_chars"]:
              raise ValueError("Value for min_chars is larger than value for max_chars.")
          # update options
          _options = MappingProxyType(_new_options)