shuffle-sdk 0.0.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ # __init__.py
2
+ from .shuffle_sdk import AppBase # Adjust the import path as necessary
3
+
4
+ __all__ = ["AppBase"] # Define the public API of your package
5
+
6
+ #print("Initializing shuffle_sdk package...")
7
+ __version__ = '0.0.3'
8
+
@@ -0,0 +1,187 @@
1
+ import re
2
+ import json
3
+
4
+ input_data = """{
5
+ "test4": $test,
6
+ "test5": ,
7
+ "test6": "what"
8
+ }
9
+ """
10
+
11
+ input_data = """{
12
+ "test0": {{ '' | default: [] }},
13
+ "test": {{ | default: [] }},
14
+ "test2": {{ $test.asd | default: [] }},
15
+ "test3": {{ {"key": "val} | default: [] }},
16
+ "test4": $test,
17
+ "test5": ,
18
+ "test6": "what"
19
+ }
20
+ """
21
+
22
+
23
+ liquiddata = "{{ $test.asd | some other stuff {{ $test.xyz | more stuff"
24
+ pattern = r'\{\{\s*\$[^|}]+\s*\|'
25
+
26
+ replaced_data = re.sub(pattern, "{{ '' |", liquiddata)
27
+ print(replaced_data)
28
+
29
+
30
+ def patternfix_string(liquiddata, patterns, regex_patterns, inputtype="liquid"):
31
+ if not inputtype or inputtype == "liquid":
32
+ if "{{" not in liquiddata or "}}" not in liquiddata:
33
+ return liquiddata
34
+ elif inputtype == "json":
35
+ liquiddata = liquiddata.strip()
36
+
37
+ # Validating if it looks like json or not
38
+ if liquiddata[0] == "{" and liquiddata[len(liquiddata)-1] == "}":
39
+ pass
40
+ else:
41
+ if liquiddata[0] == "[" and liquiddata[len(liquiddata)-1] == "]":
42
+ pass
43
+ else:
44
+ return liquiddata
45
+
46
+ # If it's already json, don't touch it
47
+ try:
48
+ json.loads(liquiddata)
49
+ return liquiddata
50
+ except Exception as e:
51
+ pass
52
+ else:
53
+ print("No replace handler for %s" % inputtype)
54
+ return liquiddata
55
+
56
+ skipkeys = [" "]
57
+ newoutput = liquiddata[:]
58
+ for pattern in patterns:
59
+ keylocations = []
60
+ parsedvalue = ""
61
+ record = False
62
+ index = -1
63
+ for key in liquiddata:
64
+
65
+ # Return instant if possible
66
+ if inputtype == "json":
67
+ try:
68
+ json.loads(newoutput)
69
+ return newoutput
70
+ except:
71
+ pass
72
+
73
+ index += 1
74
+ if not key:
75
+ if record:
76
+ keylocations.append(index)
77
+ parsedvalue += key
78
+
79
+ continue
80
+
81
+ if key in skipkeys:
82
+ if record:
83
+ keylocations.append(index)
84
+ parsedvalue += key
85
+
86
+ continue
87
+
88
+ if key == pattern[0] and not record:
89
+ record = True
90
+
91
+ if key not in pattern:
92
+ keylocations = []
93
+ parsedvalue = ""
94
+ record = False
95
+
96
+ if record:
97
+ keylocations.append(index)
98
+ parsedvalue += key
99
+
100
+ if len(parsedvalue) == 0:
101
+ continue
102
+
103
+ evaluated_value = parsedvalue[:]
104
+ for skipkey in skipkeys:
105
+ evaluated_value = "".join(evaluated_value.split(skipkey))
106
+
107
+ if evaluated_value == pattern:
108
+ #print("Found matching: %s (%s)" % (parsedvalue, keylocations))
109
+ #print("Should replace with: %s" % patterns[pattern])
110
+
111
+ newoutput = newoutput.replace(parsedvalue, patterns[pattern], -1)
112
+
113
+ # Return instant if possible
114
+ if inputtype == "json":
115
+ try:
116
+ json.loads(newoutput)
117
+ return newoutput
118
+ except:
119
+ pass
120
+
121
+
122
+ for pattern in regex_patterns:
123
+ newlines = []
124
+ for line in newoutput.split("\n"):
125
+ replaced_line = re.sub(pattern, regex_patterns[pattern], line)
126
+ newlines.append(replaced_line)
127
+
128
+ newoutput = "\n".join(newlines)
129
+
130
+ # Return instant if possible
131
+ if inputtype == "json":
132
+ try:
133
+ json.loads(newoutput)
134
+ return newoutput
135
+ except:
136
+ pass
137
+
138
+ # Dont return json properly unless actually json
139
+ if inputtype == "json":
140
+ try:
141
+ json.loads(newoutput)
142
+ return newoutput
143
+ except:
144
+ # Returns original if json fixing didn't work
145
+ return liquiddata
146
+
147
+ return newoutput
148
+
149
+ print("Start:\n%s" % input_data)
150
+
151
+ try:
152
+ newinput = patternfix_string(input_data,
153
+ {
154
+ "{{|": '{{ "" |',
155
+ },
156
+ {
157
+ #r'\{\{\s*|': "{{ '' |",
158
+ r'\{\{\s*\$[^|}]+\s*\|': '{{ "" |',
159
+ }
160
+ ,
161
+ inputtype="liquid"
162
+ )
163
+ except Exception as e:
164
+ print("[ERROR} Failed liquid parsing fix: %s" % e)
165
+ newinput = input_data
166
+
167
+ try:
168
+ newinput = patternfix_string(newinput,
169
+ {
170
+ },
171
+ {
172
+ r'\"\s*\:\s*,': '\": "",',
173
+ r'\"\s*\:\s*\$[^,]+\w*\,': '\": "",',
174
+ }
175
+ ,
176
+ inputtype="json"
177
+ )
178
+
179
+ try:
180
+ json.loads(newinput)
181
+ print("It's json! Override.")
182
+ except Exception as e:
183
+ print("Bad json. DONT use the value at all: %s" % e)
184
+ except Exception as e:
185
+ print("[ERROR} Failed json parsing fix: %s" % e)
186
+
187
+ print("\nEnd:\n%s" % newinput)
@@ -0,0 +1,326 @@
1
+ ## A test script of the recurse_json function
2
+ ## to validate that it can handle the different types of data
3
+ ## and follow the dot formation format
4
+
5
+
6
+ import re
7
+ import json
8
+
9
+ def recurse_json(basejson, parsersplit):
10
+ match = "#([0-9a-z]+):?-?([0-9a-z]+)?#?"
11
+ try:
12
+ outercnt = 0
13
+
14
+ # Loops over split values
15
+ splitcnt = -1
16
+ for value in parsersplit:
17
+ splitcnt += 1
18
+ #if " " in value:
19
+ # value = value.replace(" ", "_", -1)
20
+
21
+ actualitem = re.findall(match, value, re.MULTILINE)
22
+ # Goes here if loop
23
+ if value == "#":
24
+ newvalue = []
25
+
26
+ if basejson == None:
27
+ return "", False
28
+
29
+ for innervalue in basejson:
30
+ # 1. Check the next item (message)
31
+ # 2. Call this function again
32
+
33
+ try:
34
+ ret, is_loop = recurse_json(innervalue, parsersplit[outercnt+1:])
35
+ except IndexError:
36
+ # Only in here if it's the last loop without anything in it?
37
+ ret, is_loop = recurse_json(innervalue, parsersplit[outercnt:])
38
+
39
+ newvalue.append(ret)
40
+
41
+ # Magical way of returning which makes app sdk identify
42
+ # it as multi execution
43
+ return newvalue, True
44
+
45
+ # Checks specific regex like #1-2 for index 1-2 in a loop
46
+ elif len(actualitem) > 0:
47
+
48
+ is_loop = True
49
+ newvalue = []
50
+ firstitem = actualitem[0][0]
51
+ seconditem = actualitem[0][1]
52
+ if isinstance(firstitem, int):
53
+ firstitem = str(firstitem)
54
+ if isinstance(seconditem, int):
55
+ seconditem = str(seconditem)
56
+
57
+ #print("[DEBUG] ACTUAL PARSED: %s" % actualitem)
58
+
59
+ # Means it's a single item -> continue
60
+ if seconditem == "":
61
+ #print("[INFO] In first - handling %s. Len: %d" % (firstitem, len(basejson)))
62
+ if str(firstitem).lower() == "max" or str(firstitem).lower() == "last" or str(firstitem).lower() == "end":
63
+ firstitem = len(basejson)-1
64
+ elif str(firstitem).lower() == "min" or str(firstitem).lower() == "first":
65
+ firstitem = 0
66
+ else:
67
+ firstitem = int(firstitem)
68
+
69
+ #print(f"[DEBUG] Post lower checks with item {firstitem}")
70
+ tmpitem = basejson[int(firstitem)]
71
+ try:
72
+ newvalue, is_loop = recurse_json(tmpitem, parsersplit[outercnt+1:])
73
+ except IndexError:
74
+ newvalue, is_loop = (tmpitem, parsersplit[outercnt+1:])
75
+ else:
76
+ #print("[INFO] In ELSE - handling %s and %s" % (firstitem, seconditem))
77
+ if isinstance(firstitem, str):
78
+ if firstitem.lower() == "max" or firstitem.lower() == "last" or firstitem.lower() == "end":
79
+ firstitem = len(basejson)-1
80
+ elif firstitem.lower() == "min" or firstitem.lower() == "first":
81
+ firstitem = 0
82
+ else:
83
+ firstitem = int(firstitem)
84
+ else:
85
+ firstitem = int(firstitem)
86
+
87
+ if isinstance(seconditem, str):
88
+ if str(seconditem).lower() == "max" or str(seconditem).lower() == "last" or str(firstitem).lower() == "end":
89
+ seconditem = len(basejson)-1
90
+ elif str(seconditem).lower() == "min" or str(seconditem).lower() == "first":
91
+ seconditem = 0
92
+ else:
93
+ seconditem = int(seconditem)
94
+ else:
95
+ seconditem = int(seconditem)
96
+
97
+ #print(f"[DEBUG] Post lower checks 2: {firstitem} AND {seconditem}")
98
+ newvalue = []
99
+ if int(seconditem) > len(basejson):
100
+ seconditem = len(basejson)
101
+
102
+ for i in range(int(firstitem), int(seconditem)+1):
103
+ # 1. Check the next item (message)
104
+ # 2. Call this function again
105
+
106
+ try:
107
+ ret, tmp_loop = recurse_json(basejson[i], parsersplit[outercnt+1:])
108
+ except IndexError:
109
+ #print("[DEBUG] INDEXERROR (1): ", parsersplit[outercnt])
110
+ #ret = innervalue
111
+ ret, tmp_loop = recurse_json(basejson[i], parsersplit[outercnt:])
112
+
113
+ newvalue.append(ret)
114
+
115
+ return newvalue, is_loop
116
+
117
+ else:
118
+ if len(value) == 0:
119
+ return basejson, False
120
+
121
+ try:
122
+ if isinstance(basejson, list):
123
+ #print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (list): %s" % value)
124
+ return basejson, False
125
+ elif isinstance(basejson, bool):
126
+ #print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (bool): %s" % value)
127
+ return basejson, False
128
+ elif isinstance(basejson, int):
129
+ #print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (int): %s" % value)
130
+ return basejson, False
131
+ elif isinstance(basejson[value], str):
132
+ try:
133
+ if (basejson[value].endswith("}") and basejson[value].endswith("}")) or (basejson[value].startswith("[") and basejson[value].endswith("]")):
134
+ basejson = json.loads(basejson[value])
135
+ else:
136
+ # Should we sanitize here?
137
+ #print("[DEBUG] VALUE TO SANITIZE FOR KEY '%s'?: %s" % (value, basejson[value]))
138
+
139
+ # Check if we are on the last item?
140
+ if outercnt == len(parsersplit)-1:
141
+ #print("[DEBUG] LAST KEY")
142
+ return str(basejson[value]), False
143
+ else:
144
+ #print("[DEBUG] NOT LAST KEY")
145
+ pass
146
+
147
+ except json.decoder.JSONDecodeError as e:
148
+ return str(basejson[value]), False
149
+ else:
150
+ basejson = basejson[value]
151
+ except KeyError as e:
152
+ print("[WARNING] Running secondary value check with replacement of underscore in %s: %s" % (value, e))
153
+ if "_" in value:
154
+ value = value.replace("_", " ", -1)
155
+ elif " " in value:
156
+ value = value.replace(" ", "_", -1)
157
+
158
+ try:
159
+ if isinstance(basejson, list):
160
+ #print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (list): %s" % value)
161
+ return basejson, False
162
+ elif isinstance(basejson, bool):
163
+ #print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (bool): %s" % value)
164
+ return basejson, False
165
+ elif isinstance(basejson, int):
166
+ #print("[WARNING] VALUE IN ISINSTANCE IS NOT TO BE USED (int): %s" % value)
167
+ return basejson, False
168
+ elif isinstance(basejson[value], str):
169
+ #print(f"[INFO] LOADING STRING '%s' AS JSON" % basejson[value])
170
+ try:
171
+ #print("[DEBUG] BASEJSON: %s" % basejson)
172
+ if (basejson[value].endswith("}") and basejson[value].endswith("}")) or (basejson[value].startswith("[") and basejson[value].endswith("]")):
173
+ basejson = json.loads(basejson[value])
174
+ else:
175
+
176
+ if outercnt == len(parsersplit)-1:
177
+ #print("LAST KEY (2)")
178
+ return str(basejson[value]), False
179
+ else:
180
+ #print("NOT LAST KEY (2)")
181
+ pass
182
+
183
+ except json.decoder.JSONDecodeError as e:
184
+ #print("[DEBUG] RETURNING BECAUSE '%s' IS A NORMAL STRING (1)" % basejson[value])
185
+ return str(basejson[value]), False
186
+ else:
187
+ basejson = basejson[value]
188
+ except KeyError as e:
189
+ # Check if previous key was handled or not
190
+ previouskey = parsersplit[outercnt-1]
191
+ #print("[DEBUG] PREVIOUS KEY: ", previouskey)
192
+
193
+ tmpval = previouskey + "." + value
194
+ #print("\n\n[WARNING] Running third dot notation fix '%s' on data %s: %s" % (value, basejson, e))
195
+ if tmpval in basejson:
196
+ return basejson[tmpval], False
197
+
198
+ try:
199
+ currentsplitcnt = splitcnt
200
+
201
+ recursed_value = value
202
+ handled = False
203
+
204
+ #tmpbase = basejson
205
+ previouskey = value
206
+ while True:
207
+ #print("\n\n[DEBUG] CURRENTSPLITCNT: ", currentsplitcnt)
208
+ newvalue = parsersplit[currentsplitcnt+1]
209
+ if newvalue == "#" or newvalue == "":
210
+ break
211
+
212
+ recursed_value += "." + newvalue
213
+ #print("\n\nRECURSED: ", recursed_value)
214
+
215
+ found = False
216
+ for key, value in basejson.items():
217
+ if recursed_value.lower() in key.lower():
218
+ found = True
219
+
220
+ if found == False:
221
+ #print("[INFO] DIDN'T FIND similar VALUE: ", recursed_value)
222
+
223
+ # Check if we are on the last key or not
224
+ return "", False
225
+ #if outercnt == len(parsersplit)-1:
226
+ # print("[DEBUG] LAST KEY (3)")
227
+ # break
228
+ #else:
229
+ # print("[DEBUG] NOT LAST KEY (3)")
230
+ # return "", False
231
+
232
+ if recursed_value in basejson:
233
+ #print("[INFO] FOUND RECURSED VALUE: ", recursed_value)
234
+ basejson = basejson[recursed_value]
235
+
236
+ # Whether to dig deeper or not
237
+ if isinstance(basejson, bool) or isinstance(basejson, int) or isinstance(basejson, str):
238
+ handled = False
239
+ else:
240
+ handled = True
241
+
242
+ break
243
+
244
+ currentsplitcnt += 1
245
+
246
+ if handled:
247
+ continue
248
+
249
+ break
250
+ except IndexError as e:
251
+ print("[DEBUG] INDEXERROR (2):", parsersplit[outercnt])
252
+ return "", False
253
+
254
+ outercnt += 1
255
+
256
+ except KeyError as e:
257
+ print("[INFO] Lower keyerror: %s" % e)
258
+ return "", False
259
+ except Exception as e:
260
+ print("[WARNING] Exception: %s" % e)
261
+ return "", False
262
+
263
+ return basejson, False
264
+
265
+ print("[INFO] Starting")
266
+
267
+ #input_data = "test"
268
+ #input_data = "test2.data"
269
+
270
+
271
+
272
+ # Matchwith
273
+ basejson = {
274
+ "test": "hello",
275
+ "test2": {
276
+ "test3": "hello2",
277
+ "test3.data": "hello3",
278
+ "test4.data.testing": {
279
+ "value": "hello4"
280
+ },
281
+ "test5.data.hello": "wut",
282
+ },
283
+ "test3": ["hello", "hello2", "hello3"],
284
+ "test4": [{
285
+ "id": "1",
286
+ }]
287
+ }
288
+
289
+ # Inputexamples (ALL should be True)
290
+ inputs = {
291
+ #"": "",
292
+ "badkey": "",
293
+ "test": "hello",
294
+ "test2.badkey": "",
295
+ "test2.test3": "hello2",
296
+ "test2.test3.data": "hello3",
297
+ "test2.test4.data.testing": "{'value': 'hello4'}", # FIXME: Doesn't work due to break vs return "", False in last exception
298
+ "test2.test4.data.testing.value": "hello4", # FIXME: Doesn't work due to break vs return "", False in last exception. Not fixed as we didn't find one of these yet.
299
+ "test2.test5.data.hello": "wut",
300
+ "test2.test5.data.badkey": "",
301
+ "test3.#1": "hello2",
302
+ "test4.#0.id": "1",
303
+ "test4.#1.id": "",
304
+ }
305
+
306
+ outputs = []
307
+ for key, value in inputs.items():
308
+ parsersplit = key.split(".")
309
+ ret, is_loop = recurse_json(basejson, parsersplit)
310
+ print("\n\nOUTPUT RET (%s): %s" % (key, ret))
311
+
312
+ outputs.append("[%s]: %s = '%s' vs '%s'" % (str(ret) == str(value), key, ret, value))
313
+
314
+ print("\n\n%s" % "\n".join(outputs))
315
+
316
+ #input_data = ""
317
+ #input_data = "badkey"
318
+ #input_data = "test"
319
+ #input_data = "test2.data"
320
+ #input_data = "test2.test3.data"
321
+ #input_data = "test2.test4.data.testing.value.as"
322
+ #input_data = "test2.test5.data.hello"
323
+
324
+
325
+
326
+