1+ from __future__ import annotations
2+
13import random
24import string
3- import time
5+ from typing import Callable
46
57
68class VariableNameGenerator :
7- def __init__ (self ):
8- self .generator_options = [
9+ """Generates obfuscated-looking variable names.
10+
11+ Pass a seeded :class:`random.Random` instance for reproducible output::
12+
13+ gen = VariableNameGenerator(rng=random.Random(42))
14+ """
15+
16+ def __init__ (self , rng : random .Random | None = None ) -> None :
17+ self ._rng = rng or random .Random ()
18+ self ._generator_options : list [Callable [[int ], str ]] = [
919 self .random_string ,
1020 self .l_and_i ,
1121 self .time_based ,
@@ -14,33 +24,29 @@ def __init__(self):
1424 self .single_letter_a_lot ,
1525 ]
1626
17- def get_random (self , id ) :
18- return random . choice (self .generator_options )(id )
27+ def get_random (self , id : int ) -> str :
28+ return self . _rng . choice (self ._generator_options )(id )
1929
20- def random_string (self , id , length = 79 ):
21- # Why is it 79 by default?
22- # See: https://stackoverflow.com/a/16920876/11472374
23- # As kirelagin commented readability is very important
30+ def random_string (self , id : int , length : int = 79 ) -> str :
31+ # 79 chars: see https://stackoverflow.com/a/16920876/11472374
2432 return "" .join (
25- random . choice (string .ascii_letters ) for i in range (length )
33+ self . _rng . choice (string .ascii_letters ) for _ in range (length )
2634 ) + str (id )
2735
28- def l_and_i (self , id ) :
29- return "" .join (random . choice ("Il" ) for i in range (id ))
36+ def l_and_i (self , id : int ) -> str :
37+ return "" .join (self . _rng . choice ("Il" ) for _ in range (id ))
3038
31- def time_based (self , id ):
32- return (
33- random .choice (string .ascii_letters )
34- + str (time .time ()).replace ("." , "" )
35- + str (id )
36- )
39+ def time_based (self , id : int ) -> str :
40+ # Use the rng to produce a large pseudo-time value so that this
41+ # generator is fully deterministic when the rng is seeded.
42+ pseudo_time = str (self ._rng .randint (10 ** 12 , 10 ** 13 ))
43+ return self ._rng .choice (string .ascii_letters ) + pseudo_time + str (id )
3744
38- def just_id (self , id ):
39- # python doesn't work with numbers for variable names
40- return random .choice (string .ascii_letters ) + str (id )
45+ def just_id (self , id : int ) -> str :
46+ return self ._rng .choice (string .ascii_letters ) + str (id )
4147
42- def scream (self , id ) :
43- return "" .join (random . choice ("Aa" ) for i in range (id ))
48+ def scream (self , id : int ) -> str :
49+ return "" .join (self . _rng . choice ("Aa" ) for _ in range (id ))
4450
45- def single_letter_a_lot (self , id ) :
46- return random .choice (string .ascii_letters ) * id
51+ def single_letter_a_lot (self , id : int ) -> str :
52+ return self . _rng .choice (string .ascii_letters ) * id
0 commit comments