"""
utils for testing
"""
import os
import random
import string
from functools import reduce
from operator import add
from py2store.key_mappers.tuples import (
dict_of_tuple,
str_of_tuple,
dsv_of_list,
)
from py2store.key_mappers.str_utils import (
n_format_params_in_str_format,
empty_arg_and_kwargs_for_format,
)
# Note: Probably want to use another package for generation of fake data.
# For example, https://github.com/joke2k/faker
lower_case_letters = string.ascii_lowercase
alphanumeric = string.digits + lower_case_letters
non_alphanumeric = ''.join(set(string.printable).difference(alphanumeric))
[docs]def random_word(length, alphabet, concat_func=add):
"""Make a random word by concatenating randomly drawn elements from alphabet together
Args:
length: Length of the word
alphabet: Alphabet to draw from
concat_func: The concatenation function (e.g. + for strings and lists)
Note: Repeated elements in alphabet will have more chances of being drawn.
Returns:
A word (whose type depends on what concatenating elements from alphabet produces).
Not making this a proper doctest because I don't know how to seed the global random temporarily
>>> t = random_word(4, 'abcde'); # e.g. 'acae'
>>> t = random_word(5, ['a', 'b', 'c']); # e.g. 'cabba'
>>> t = random_word(4, [[1, 2, 3], [40, 50], [600], [7000]]); # e.g. [40, 50, 7000, 7000, 1, 2, 3]
>>> t = random_word(4, [1, 2, 3, 4]); # e.g. 13 (because adding numbers...)
>>> # ... sometimes it's what you want:
>>> t = random_word(4, [2 ** x for x in range(8)]); # e.g. 105 (binary combination)
>>> t = random_word(4, [1, 2, 3, 4], concat_func=lambda x, y: str(x) + str(y)); # e.g. '4213'
>>> t = random_word(4, [1, 2, 3, 4], concat_func=lambda x, y: int(str(x) + str(y))); # e.g. 3432
"""
if isinstance(alphabet, bytes) or isinstance(alphabet[0], bytes):
# convert to list of bytes, or the function will return ints instead of bytes
alphabet = _list_of_bytes_singletons(alphabet)
return reduce(
concat_func, (random.choice(alphabet) for _ in range(length))
)
def _list_of_bytes_singletons(bytes_alphabet):
"""Convert to list of bytes, or the function will return ints instead of bytes"""
return list(map(lambda x: bytes([x]), bytes_alphabet))
[docs]def random_string(length=7, alphabet=lower_case_letters):
"""Same as random_word, but it optimized for strings
(5-10% faster for words of length 7, 25-30% faster for words of size 1000)"""
return ''.join(random.choice(alphabet) for _ in range(length))
[docs]def random_word_gen(
word_size_range=(1, 10), alphabet=lower_case_letters, n=100
):
"""Random string generator
Args:
word_size_range: An int, 2-tuple of ints, or list-like object that defines the choices of word sizes
alphabet: A string or iterable defining the alphabet to draw from
n: The number of elements the generator will yield
Returns:
Random string generator
"""
if isinstance(word_size_range, int):
word_size_range = range(1, word_size_range + 1)
elif not isinstance(word_size_range, range):
word_size_range = range(*word_size_range)
for _ in range(n):
length = random.choice(word_size_range)
yield random_word(length, alphabet)
[docs]def random_tuple_gen(
tuple_length=3,
word_size_range=(1, 10),
alphabet=lower_case_letters,
n: int = 100,
):
"""Random tuple (of strings) generator
Args:
tuple_length: The length of the tuples generated
word_size_range: An int, 2-tuple of ints, or list-like object that defines the choices of word sizes
alphabet: A string or iterable defining the alphabet to draw from
n: The number of elements the generator will yield
Returns:
Random tuple (of strings) generator
"""
for _ in range(n):
yield tuple(random_word_gen(word_size_range, alphabet, tuple_length))
[docs]def random_dict_gen(
fields=('a', 'b', 'c'),
word_size_range=(1, 10),
alphabet=lower_case_letters,
n: int = 100,
):
"""Random dict (of strings) generator
Args:
fields: Field names for the random dicts
word_size_range: An int, 2-tuple of ints, or list-like object that defines the choices of word sizes
alphabet: A string or iterable defining the alphabet to draw from
n: The number of elements the generator will yield
Returns:
Random dict (of strings) generator
"""
tuple_length = len(fields)
yield from (
dict_of_tuple(x, fields)
for x in random_tuple_gen(tuple_length, word_size_range, alphabet, n)
)
########################################################################################################################
# s3 utils
def extract_s3_access_info(access_dict):
return {
'bucket_name': access_dict['bucket'],
'aws_access_key_id': access_dict['access'],
'aws_secret_access_key': access_dict['secret'],
}
def _s3_env_var_name(kind, perm='RO'):
kind = kind.upper()
perm = perm.upper()
assert kind in {
'BUCKET',
'ACCESS',
'SECRET',
}, "kind should be in {'BUCKET', 'ACCESS', 'SECRET'}"
assert perm in {'RW', 'RO'}, "perm should be in {'RW', 'RO'}"
return 'S3_TEST_{kind}_{perm}'.format(kind=kind, perm=perm)
def get_s3_test_access_info_from_env_vars(perm=None):
if perm is None:
try:
return get_s3_test_access_info_from_env_vars(perm='RO')
except LookupError:
return get_s3_test_access_info_from_env_vars(perm='RW')
else:
access_keys = dict()
for kind in {'BUCKET', 'ACCESS', 'SECRET'}:
k = _s3_env_var_name(kind, perm)
if k not in os.environ:
raise LookupError(
"Couldn't find the environment variable: {}".format(k)
)
else:
access_keys[kind.lower()] = os.environ[k]
return extract_s3_access_info(access_keys)