33
44from  typing  import  Union , Any 
55from  uuid  import  UUID 
6+ import  string 
7+ 
8+ alphanums  =  string .digits  +  string .ascii_lowercase 
69
710
811def  safezip (* args ):
@@ -16,24 +19,99 @@ def split_space(start, end, count):
1619 return  list (range (start , end , (size  +  1 ) //  (count  +  1 )))[1  : count  +  1 ]
1720
1821
19- class  ArithUUID (UUID ):
22+ class  ArithString :
23+  @classmethod  
24+  def  new (cls , * args , ** kw ):
25+  return  cls (* args , ** kw )
26+ 
27+ 
28+ class  ArithUUID (UUID , ArithString ):
2029 "A UUID that supports basic arithmetic (add, sub)" 
2130
31+  def  __int__ (self ):
32+  return  self .int 
33+ 
2234 def  __add__ (self , other : Union [UUID , int ]):
2335 if  isinstance (other , int ):
24-  return  type ( self ) (int = self .int  +  other )
36+  return  self . new (int = self .int  +  other )
2537 return  NotImplemented 
2638
2739 def  __sub__ (self , other : Union [UUID , int ]):
2840 if  isinstance (other , int ):
29-  return  type ( self ) (int = self .int  -  other )
41+  return  self . new (int = self .int  -  other )
3042 elif  isinstance (other , UUID ):
3143 return  self .int  -  other .int 
3244 return  NotImplemented 
3345
46+ 
47+ def  numberToBase (num , base ):
48+  digits  =  []
49+  while  num  >  0 :
50+  num , remainder  =  divmod (num , base )
51+  digits .append (remainder )
52+  return  "" .join (alphanums [i ] for  i  in  digits [::- 1 ])
53+ 
54+ 
55+ class  ArithAlphanumeric (ArithString ):
56+  def  __init__ (self , str : str  =  None , int : int  =  None , max_len = None ):
57+  if  str  is  None :
58+  str  =  numberToBase (int , len (alphanums ))
59+  else :
60+  assert  int  is  None 
61+ 
62+  if  max_len  and  len (str ) >  max_len :
63+  raise  ValueError (f"Length of alphanum value '{ str } { max_len }  )
64+ 
65+  self ._str  =  str 
66+  self ._max_len  =  max_len 
67+ 
68+  @property  
69+  def  int (self ):
70+  return  int (self ._str , len (alphanums ))
71+ 
72+  def  __str__ (self ):
73+  s  =  self ._str 
74+  if  self ._max_len :
75+  s  =  s .rjust (self ._max_len , "0" )
76+  return  s 
77+ 
78+  def  __len__ (self ):
79+  return  len (self ._str )
80+ 
3481 def  __int__ (self ):
3582 return  self .int 
3683
84+  def  __repr__ (self ):
85+  return  f'alphanum"{ self ._str }  
86+ 
87+  def  __add__ (self , other : "Union[ArithAlphanumeric, int]" ):
88+  if  isinstance (other , int ):
89+  res  =  self .new (int = self .int  +  other )
90+  if  len (str (res )) !=  len (self ):
91+  raise  ValueError ("Overflow error when adding to alphanumeric" )
92+  return  res 
93+  return  NotImplemented 
94+ 
95+  def  __sub__ (self , other : "Union[ArithAlphanumeric, int]" ):
96+  if  isinstance (other , int ):
97+  return  type (self )(int = self .int  -  other )
98+  elif  isinstance (other , ArithAlphanumeric ):
99+  return  self .int  -  other .int 
100+  return  NotImplemented 
101+ 
102+  def  __ge__ (self , other ):
103+  if  not  isinstance (other , type (self )):
104+  return  NotImplemented 
105+  return  self .int  >=  other .int 
106+ 
107+  def  __lt__ (self , other ):
108+  if  not  isinstance (other , type (self )):
109+  return  NotImplemented 
110+  return  self .int  <  other .int 
111+ 
112+  def  new (self , * args , ** kw ):
113+  return  type (self )(* args , ** kw , max_len = self ._max_len )
114+ 
37115
38116def  is_uuid (u ):
39117 try :
@@ -57,23 +135,24 @@ def number_to_human(n):
57135def  _join_if_any (sym , args ):
58136 args  =  list (args )
59137 if  not  args :
60-  return  '' 
138+  return  "" 
61139 return  sym .join (str (a ) for  a  in  args  if  a )
62140
63- def  remove_password_from_url (url : str , replace_with : str = "***" ) ->  str :
141+ 
142+ def  remove_password_from_url (url : str , replace_with : str  =  "***" ) ->  str :
64143 parsed  =  urlparse (url )
65-  account  =  parsed .username  or  '' 
144+  account  =  parsed .username  or  "" 
66145 if  parsed .password :
67-  account  +=  ':'  +  replace_with 
146+  account  +=  ":"  +  replace_with 
68147 host  =  _join_if_any (":" , filter (None , [parsed .hostname , parsed .port ]))
69148 netloc  =  _join_if_any ("@" , filter (None , [account , host ]))
70149 replaced  =  parsed ._replace (netloc = netloc )
71150 return  replaced .geturl ()
72151
152+ 
73153def  join_iter (joiner : Any , iterable : iter ) ->  iter :
74154 it  =  iter (iterable )
75155 yield  next (it )
76156 for  i  in  it :
77157 yield  joiner 
78158 yield  i 
79- 
0 commit comments