import io
import random
from datetime import datetime
from functools import partial
from random import _inst as _DEFAULT_RANDOM
from typing import Optional
from .binary import random_bytes
from ..encoding import md5, sha1, base64_encode
__all__ = [
'random_digits', 'random_bin_digits', 'random_hex_digits',
'random_md5', 'random_sha1', 'random_base64',
'random_md5_with_timestamp', 'random_sha1_with_timestamp',
]
def _check_base(base: int):
if base < 2:
raise ValueError(f'Base should be an integer no less than 2, but {repr(base)} found.')
elif base > 36:
raise ValueError(f'Base should be an integer no greater then 36, but {repr(base)} found.')
elif not isinstance(base, int):
raise TypeError(f'Base should be an integer, but {repr(type(base))} found.')
_0_ASCII = ord('0')
_LOWER_A_ASCII = ord('a')
_UPPER_A_ASCII = ord('A')
def _random_dchar(base: int, upper: bool, rnd: random.Random):
_val = rnd.randint(0, base - 1)
if _val < 10:
_base = _0_ASCII
elif upper:
_base = _UPPER_A_ASCII - 10
else:
_base = _LOWER_A_ASCII - 10
return chr(_base + _val)
[docs]def random_digits(length: int = 32, base: int = 10, upper: bool = False, rnd: Optional[random.Random] = None) -> str:
"""
Overview:
Create random digits.
Arguments:
- length (:obj:`int`): Length of the digits, default is 32.
- base (:obj:`int`): Base of the digits, should be in [2, 36], default is 10.
- upper (:obj:`bool`): Upper the hex chars, default is ``False``.
- rnd (:obj:`Optional[random.Random]`): Random object you used, \
default is ``None`` which means just use the default one provided by system.
Returns:
- string (:obj:`str`): Random digital string.
Examples::
>>> from hbutils.random import random_digits
>>> random_digits()
'53518555004529024184262875530824'
>>> random_digits(base=8)
'77337055655313664176450107031511'
>>> random_digits(48, base=8)
'130107050101775254773050732461131017135371516420'
"""
_check_base(base)
rnd = rnd or _DEFAULT_RANDOM
with io.StringIO() as sio:
for i in range(length):
sio.write(_random_dchar(base, upper, rnd))
return sio.getvalue()
[docs]def random_bin_digits(length: int = 32, rnd: Optional[random.Random] = None) -> str:
"""
Overview:
Create random binary digits.
Arguments:
- length (:obj:`int`): Length of the digits, default is 32.
- rnd (:obj:`Optional[random.Random]`): Random object you used, \
default is ``None`` which means just use the default one provided by system.
Returns:
- string (:obj:`str`): Random binary digital string.
Examples::
>>> from hbutils.random import random_bin_digits
>>> random_bin_digits()
'11001011010101101100011010010011'
>>> random_bin_digits(48)
'010110000110101101111111011100010011101011010100'
"""
return random_digits(length, 2, False, rnd)
[docs]def random_hex_digits(length: int = 32, upper: bool = False, rnd: Optional[random.Random] = None) -> str:
"""
Overview:
Create random hexidecimal digits.
Arguments:
- length (:obj:`int`): Length of the digits, default is 32.
- rnd (:obj:`Optional[random.Random]`): Random object you used, \
default is ``None`` which means just use the default one provided by system.
Returns:
- string (:obj:`str`): Random hexidecimal digital string.
Examples::
>>> from hbutils.random import random_hex_digits
>>> random_hex_digits()
'bf4eadfb8c1700d74024833c3ce211a7'
>>> random_hex_digits(upper=True)
'7B85DE69A319BA132ACA27C7777A1C3E'
>>> random_hex_digits(48)
'7175a23730391687b7b5230c72d702a1664833a1c66783cc'
"""
return random_digits(length, 16, upper, rnd)
_RANDOM_BYTES_LENGTH = 64
def _random_hash(hash_func, length: int = _RANDOM_BYTES_LENGTH, rnd: Optional[random.Random] = None):
return hash_func(random_bytes(length, allow_zero=False, rnd=rnd))
[docs]def random_md5(rnd: Optional[random.Random] = None) -> str:
"""
Overview:
Create random md5 string.
Arguments:
- rnd (:obj:`Optional[random.Random]`): Random object you used, \
default is ``None`` which means just use the default one provided by system.
Returns:
- string (:obj:`str`): Random md5 string.
Examples::
>>> from hbutils.random import random_md5
>>> random_md5()
'bbffd8913a7c49161ebe31b9092a9016'
"""
return _random_hash(md5, _RANDOM_BYTES_LENGTH, rnd)
[docs]def random_sha1(rnd: Optional[random.Random] = None) -> str:
"""
Overview:
Create random sha1 string.
Arguments:
- rnd (:obj:`Optional[random.Random]`): Random object you used, \
default is ``None`` which means just use the default one provided by system.
Returns:
- string (:obj:`str`): Random sha1 string.
Examples::
>>> from hbutils.random import random_sha1
>>> random_sha1()
'13135aa6b05482dcdbc1f5a25d117298571e7fab'
"""
return _random_hash(sha1, _RANDOM_BYTES_LENGTH, rnd)
[docs]def random_base64(length: int = _RANDOM_BYTES_LENGTH, rnd: Optional[random.Random] = None) -> str:
"""
Overview:
Create random base64, may be useful when matrix verification code.
Arguments:
- length (:obj:`int`): Length of the original binary data, default is 64.
- rnd (:obj:`Optional[random.Random]`): Random object you used, \
default is ``None`` which means just use the default one provided by system.
Returns:
- string (:obj:`str`): Random base64 string.
Examples::
>>> from hbutils.random import random_base64
>>> random_base64()
'PJZzHkM2-DpeXn1W9b3rp0I66MnOeD-31d2XYTA3va7N8DSNmQgvIINnvDMKWaRW-WHo_ftgKHg40z7XbDupbg=='
>>> random_base64(48)
'siRZNSeytSUXlIgKYuZOzbhehhI7oabcxFDB07PkjyZ5b0DI5hGC0pqjJFlD6NGQ'
"""
return _random_hash(partial(base64_encode, urlsafe=True), length, rnd)
def _timestamp():
return datetime.now().strftime("%Y%m%d%H%M%S%f")
[docs]def random_md5_with_timestamp(rnd: Optional[random.Random] = None) -> str:
"""
Overview:
Create random md5 string with timestamp.
Arguments:
- rnd (:obj:`Optional[random.Random]`): Random object you used, \
default is ``None`` which means just use the default one provided by system.
Returns:
- string (:obj:`str`): Random md5 string with timestamp.
Examples::
>>> from hbutils.random import random_md5_with_timestamp
>>> random_md5_with_timestamp()
'20220116233104357175_daf67fde4b758ff4aae21cc77f5ed689'
"""
return f'{_timestamp()}_{random_md5(rnd)}'
[docs]def random_sha1_with_timestamp(rnd: Optional[random.Random] = None) -> str:
"""
Overview:
Create random sha1 string with timestamp.
Arguments:
- rnd (:obj:`Optional[random.Random]`): Random object you used, \
default is ``None`` which means just use the default one provided by system.
Returns:
- string (:obj:`str`): Random sha1 string with timestamp.
Examples::
>>> from hbutils.random import random_sha1_with_timestamp
>>> random_sha1_with_timestamp()
'20220116233121916685_fba840b80163b55cd2295d84286a438bf8acb7c0'
"""
return f'{_timestamp()}_{random_sha1(rnd)}'