@@ -19,32 +19,85 @@ def _merge_options(self, options):
1919 options = {** DEFAULT_OPTIONS , ** options }
2020 self ._options = options
2121
22- assert self ._options .get ("separator" , "dot" ) in ["dot" , "bracket" ]
22+ assert self ._options .get ("separator" , "dot" ) in [
23+ "dot" , "bracket" , "mixed" ]
2324 assert isinstance (self ._options .get ("raise_duplicate" , False ), bool )
2425 assert isinstance (self ._options .get ("assign_duplicate" , False ), bool )
2526
26- self ._is_dot = self ._options ["separator" ] == "dot"
27- if not self .is_dot :
27+ self .__is_dot = False
28+ self .__is_mixed = False
29+ self .__is_bracket = False
30+ if self ._options ["separator" ] == "dot" :
31+ self .__is_dot = True
32+ elif self ._options ["separator" ] == "mixed" :
33+ self .__is_mixed = True
34+ else :
35+ self .__is_bracket = True
2836 self ._reg = re .compile (r"\[|\]" )
2937
30- @property
31- def is_dot (self ):
32- return self ._is_dot
38+ def mixed_split (self , key ):
39+ def span (key , i ):
40+ old = i
41+ while i != len (key ):
42+ if key [i ] in ".[]" :
43+ break
44+ i += 1
45+ if old == i :
46+ raise ValueError (
47+ f"invalid format key '{ full_keys } ', empty key value at position { i + pos } " )
48+ return i
49+
50+ full_keys = key
51+ idx = span (key , 0 )
52+ pos = idx
53+ keys = [key [:idx ]]
54+ key = key [idx :]
55+
56+ i = 0
57+ while i < len (key ):
58+ if key [i ] == '.' :
59+ i += 1
60+ idx = span (key , i )
61+ keys .append (key [i : idx ])
62+ i = idx
63+ elif key [i ] == '[' :
64+ i += 1
65+ idx = span (key , i )
66+ if key [idx ] != ']' :
67+ raise ValueError (
68+ f"invalid format key '{ full_keys } ', not end with bracket at position { i + pos } " )
69+ sub = key [i : idx ]
70+ if not sub .isdigit ():
71+ raise ValueError (
72+ f"invalid format key '{ full_keys } ', list key is not a valid number at position { i + pos } " )
73+ keys .append (int (key [i : idx ]))
74+ i = idx + 1
75+ elif key [i ] == ']' :
76+ raise ValueError (
77+ f"invalid format key '{ full_keys } ', not start with bracket at position { i + pos } " )
78+ else :
79+ raise ValueError (
80+ f"invalid format key '{ full_keys } ', invalid char at position { i + pos } " )
81+ return keys
3382
3483 def split_key (self , key ):
3584 # remove space
3685 k = key .replace (" " , "" )
86+ if len (k ) != len (key ):
87+ raise Exception (f"invalid format from key { key } , no space allowed" )
3788
3889 # remove empty string and count key length for check is a good format
3990 # reduce + filter are a hight cost so do manualy with for loop
4091
4192 # optimize by split with string func
42- if self .is_dot :
93+ if self .__is_mixed :
94+ return self .mixed_split (key )
95+ if self .__is_dot :
4396 length = 1
44- splitter = k .split ("." )
97+ splitter = key .split ("." )
4598 else :
4699 length = 2
47- splitter = self ._reg .split (k )
100+ splitter = self ._reg .split (key )
48101
49102 check = - length
50103
@@ -54,7 +107,7 @@ def split_key(self, key):
54107 results .append (select )
55108 check += len (select ) + length
56109
57- if len (k ) != check :
110+ if len (key ) != check :
58111 raise Exception (f"invalid format from key { key } " )
59112 return results
60113
@@ -79,8 +132,10 @@ def set_type(self, dtc, key, value, full_keys, prev=None, last=False):
79132 return self .set_type (dtc [prev ['key' ]], key , value , full_keys , prev , last )
80133 return key
81134
82- def get_next_type (self , keys ):
83- return [] if keys .isdigit () else {}
135+ def get_next_type (self , key ):
136+ if self .__is_mixed :
137+ return [] if isinstance (key , int ) else {}
138+ return [] if key .isdigit () else {}
84139
85140 def convert_value (self , data , key ):
86141 return data [key ]
0 commit comments