-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathgeneration.py
More file actions
140 lines (100 loc) · 3.92 KB
/
generation.py
File metadata and controls
140 lines (100 loc) · 3.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# -*- coding: utf-8 -*-
# public api to export
__all__ = [
'uuid',
'random_string',
'secure_random_hex',
'roman_range',
]
import binascii
import os
import random
import string
from typing import Generator
from uuid import uuid4
from .manipulation import roman_encode
def uuid(as_hex: bool = False) -> str:
"""
Generated an UUID string (using `uuid.uuid4()`).
*Examples:*
>>> uuid() # possible output: '97e3a716-6b33-4ab9-9bb1-8128cb24d76b'
>>> uuid(as_hex=True) # possible output: '97e3a7166b334ab99bb18128cb24d76b'
:param as_hex: True to return the hex value of the UUID, False to get its default representation (default).
:return: uuid string.
"""
uid = uuid4()
if as_hex:
return uid.hex
return str(uid)
def random_string(size: int) -> str:
"""
Returns a string of the specified size containing random characters (uppercase/lowercase ascii letters and digits).
*Example:*
>>> random_string(9) # possible output: "cx3QQbzYg"
:param size: Desired string size
:type size: int
:return: Random string
"""
if not isinstance(size, int) or size < 1:
raise ValueError('size must be >= 1')
chars = string.ascii_letters + string.digits
buffer = [random.choice(chars) for _ in range(size)]
out = ''.join(buffer)
return out
def secure_random_hex(byte_count: int) -> str:
"""
Generates a random string using secure low level random generator (os.urandom).
**Bear in mind**: due to hex conversion, the returned string will have a size that is exactly\
the double of the given `byte_count`.
*Example:*
>>> secure_random_hex(9) # possible output: 'aac4cf1d1d87bd5036'
:param byte_count: Number of random bytes to generate
:type byte_count: int
:return: Hexadecimal string representation of generated random bytes
"""
if not isinstance(byte_count, int) or byte_count < 1:
raise ValueError('byte_count must be >= 1')
random_bytes = os.urandom(byte_count)
hex_bytes = binascii.hexlify(random_bytes)
hex_string = hex_bytes.decode()
return hex_string
def roman_range(stop: int, start: int = 1, step: int = 1) -> Generator:
"""
Similarly to native Python's `range()`, returns a Generator object which generates a new roman number
on each iteration instead of an integer.
*Example:*
>>> for n in roman_range(7): print(n)
>>> # prints: I, II, III, IV, V, VI, VII
>>> for n in roman_range(start=7, stop=1, step=-1): print(n)
>>> # prints: VII, VI, V, IV, III, II, I
:param stop: Number at which the generation must stop (must be <= 3999).
:param start: Number at which the generation must start (must be >= 1).
:param step: Increment of each generation step (default to 1).
:return: Generator of roman numbers.
"""
def validate(arg_value, arg_name, allow_negative=False):
msg = '"{}" must be an integer in the range 1-3999'.format(arg_name)
if not isinstance(arg_value, int):
raise ValueError(msg)
if allow_negative:
arg_value = abs(arg_value)
if arg_value < 1 or arg_value > 3999:
raise ValueError(msg)
def generate():
current = start
# generate values for each step
while current != stop:
yield roman_encode(current)
current += step
# last value to return
yield roman_encode(current)
# checks each single argument value
validate(stop, 'stop')
validate(start, 'start')
validate(step, 'step', allow_negative=True)
# checks if the provided configuration leads to a feasible iteration with respect to boundaries or not
forward_exceed = step > 0 and (start > stop or start + step > stop)
backward_exceed = step < 0 and (start < stop or start + step < stop)
if forward_exceed or backward_exceed:
raise OverflowError('Invalid start/stop/step configuration')
return generate()