Skip to content

Commit 47c9271

Browse files
committed
[fix] change to __init__.py
1 parent ea55b48 commit 47c9271

File tree

2 files changed

+238
-231
lines changed

2 files changed

+238
-231
lines changed

src/csv_to_custom_json/__init__.py

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
'''
2+
csv_to_custom_json by n4n5
3+
'''
4+
from csv import reader as CSVreader
5+
from os.path import isfile
6+
from json import dumps as JSONstringify
7+
8+
# pylint: disable=W0102
9+
# -> dangerous arguments
10+
# pylint: disable=C0103
11+
# -> Function name "parseFile"
12+
13+
14+
def parseFile(path_to_file="", schema=None, options_user={}):
15+
"""Global function to parse a file"""
16+
def check_options(options_user, attr, default_value):
17+
""" Check options or put default value """
18+
if attr in options_user:
19+
return options_user[attr]
20+
return default_value
21+
options = {
22+
"arrayParse": check_options(options_user, "arrayParse", True),
23+
"callBackForce": check_options(options_user, "callBackForce", False),
24+
"debug": check_options(options_user, "debug", False),
25+
"error": check_options(options_user, "error", False),
26+
"lineCallBack": check_options(options_user, "lineCallBack", None),
27+
"parse": check_options(options_user, "parse", True),
28+
"separator": check_options(options_user, "separator", ","),
29+
"privateSeparator": check_options(options_user, "privateSeparator", "..."),
30+
"overrideFirstLine": check_options(options_user, "overrideFirstLine", False),
31+
"avoidVoidLine": check_options(options_user, "avoidVoidLine", False)
32+
}
33+
if options["debug"]:
34+
if isinstance(schema, (list, dict)) and schema is not None:
35+
print("HAS SCHEMA")
36+
else:
37+
print("NO SCHEMA")
38+
print("OPTIONS", JSONstringify(options))
39+
if options["error"] == "no":
40+
print("Useless informations : just use try catch if you don't want error :)")
41+
if isinstance(path_to_file, str):
42+
if not isfile(path_to_file):
43+
if options["error"] == "no":
44+
return []
45+
raise ValueError(
46+
"Can't access to the file : '{}'".format(path_to_file))
47+
48+
if isinstance(path_to_file, str):
49+
csv_file = open(path_to_file)
50+
line_reader = CSVreader(csv_file, delimiter=options["separator"])
51+
elif isinstance(path_to_file, list):
52+
line_reader = path_to_file
53+
54+
def create_fields_binding(schema_object, first_line, start_path=""):
55+
""" Create fields bindings """
56+
bindings = []
57+
for index, value in enumerate(schema_object):
58+
is_list = isinstance(schema_object, list)
59+
is_dict = isinstance(schema_object, dict)
60+
if is_list:
61+
one_element = index
62+
elif is_dict:
63+
one_element = value
64+
if start_path == "":
65+
path = '{}'.format(one_element)
66+
else:
67+
path = '{}{}{}'.format(
68+
start_path, options["privateSeparator"], one_element)
69+
if isinstance(schema_object[one_element], (dict, list)):
70+
if isinstance(schema_object[one_element], list):
71+
bindings.append({
72+
"name": one_element,
73+
"path": path,
74+
"type": "helper-array"
75+
})
76+
bindings = bindings + \
77+
create_fields_binding(
78+
schema_object[one_element], first_line, path)
79+
else:
80+
if is_list and options["arrayParse"] and schema_object[one_element] in first_line:
81+
bindings.append({
82+
"name": schema_object[one_element],
83+
"path": path,
84+
"value": "string"
85+
})
86+
else:
87+
if one_element in first_line or callable(schema_object[one_element]):
88+
bindings.append({
89+
"name": one_element,
90+
"path": path,
91+
"value": schema_object[one_element]
92+
})
93+
else:
94+
bindings.append({
95+
"name": one_element,
96+
"path": path,
97+
"type": "static",
98+
"value": schema_object[one_element]
99+
})
100+
return bindings
101+
102+
def parse_line(line, rows, first_line):
103+
"""" Parse one line """
104+
if isinstance(schema, list):
105+
obj = []
106+
else:
107+
obj = {}
108+
all_values = line
109+
for one_row in rows:
110+
one_path_row = one_row["path"]
111+
one_path_name = one_row["name"]
112+
all_path = one_path_row.split(options["privateSeparator"])
113+
current_value = None
114+
if ('type' not in one_row) or ('type' in one_row and one_row["type"] is None):
115+
if 'value' not in one_row:
116+
schema_value = None
117+
else:
118+
schema_value = one_row["value"]
119+
if one_row["name"] in first_line:
120+
index = first_line.index(one_row["name"])
121+
else:
122+
index = -1
123+
if index == -1:
124+
current_value = schema_value
125+
else:
126+
if index < len(all_values):
127+
current_value = all_values[index]
128+
if options["parse"] and current_value is not None:
129+
if schema_value == "int" and current_value != '':
130+
current_value = int(current_value)
131+
elif schema_value == "float":
132+
current_value = float(current_value)
133+
elif schema_value == "string":
134+
current_value = str(current_value)
135+
elif callable(schema_value):
136+
if callable(current_value):
137+
# When the value is in an array
138+
current_value = schema_value(all_values)
139+
else:
140+
current_value = schema_value(current_value)
141+
elif ('type' in one_row and one_row["type"] == "helper-array"):
142+
current_value = []
143+
elif ('type' in one_row and one_row["type"] == "static"):
144+
current_value = one_row["value"]
145+
good_place = None
146+
if len(all_path) > 1:
147+
good_place = obj
148+
long = len(all_path)
149+
for count in range(0, long):
150+
next_path = all_path[count]
151+
if isinstance(good_place, list):
152+
next_path_int = int(next_path)
153+
if count == (long - 1):
154+
if isinstance(good_place, dict):
155+
good_place[next_path] = ""
156+
else:
157+
if (isinstance(good_place, list) and next_path_int not in good_place) or next_path not in good_place:
158+
if isinstance(good_place, list):
159+
if len(good_place) < (next_path_int+1):
160+
# len() returns 0 and the first index of the list is 0 !
161+
good_place.insert(next_path_int, {})
162+
else:
163+
good_place[next_path] = {}
164+
if isinstance(good_place, list):
165+
if next_path_int < len(good_place):
166+
good_place = good_place[next_path_int]
167+
else:
168+
good_place = good_place[next_path]
169+
if isinstance(good_place, list):
170+
good_place.append(current_value)
171+
elif isinstance(good_place, dict):
172+
good_place[one_path_name] = current_value
173+
else:
174+
good_place = current_value
175+
else:
176+
if isinstance(obj, list):
177+
place = int(one_path_row)
178+
obj.insert(place, current_value)
179+
elif isinstance(obj, dict):
180+
obj[one_path_row] = current_value
181+
return obj
182+
183+
def parse_first_line(first_line):
184+
""" Parse the first line """
185+
if schema is not None:
186+
# None is default value for schema
187+
cols = create_fields_binding(schema, first_line)
188+
if options["debug"]:
189+
print("BINDINGS:", JSONstringify(
190+
cols, default=lambda o: '<not serializable>'))
191+
else:
192+
def dupli(element):
193+
"""" Duplicate the first line """
194+
return {
195+
"name": element,
196+
"path": element
197+
}
198+
cols = [dupli(x) for x in first_line]
199+
return cols
200+
201+
def reader(line_reader):
202+
"""" Read the file """
203+
final_json = []
204+
if isinstance(path_to_file, str):
205+
first_line = next(line_reader)
206+
elif isinstance(path_to_file, list):
207+
first_line = line_reader[0].split(options["separator"])
208+
line_reader = line_reader[1:]
209+
if isinstance(options["overrideFirstLine"], list):
210+
first_line = options["overrideFirstLine"]
211+
rows = parse_first_line(first_line)
212+
for one_line in line_reader:
213+
parsed_line = {}
214+
if isinstance(path_to_file, list):
215+
one_line = one_line.split(options["separator"])
216+
elif isinstance(path_to_file, str) and isinstance(one_line, list) and not one_line:
217+
one_line = [''] # create a fake void line
218+
if options["avoidVoidLine"]:
219+
if (isinstance(one_line, list) and not one_line) or (isinstance(one_line, list) and len(one_line) >= 1 and one_line[0] == "") or one_line == "" or one_line == "\n" or one_line == "\r\n":
220+
continue
221+
parsed_line = parse_line(one_line, rows, first_line)
222+
if callable(options["lineCallBack"]):
223+
res_callback = options["lineCallBack"](parsed_line, one_line)
224+
if res_callback is None:
225+
if options["callBackForce"]:
226+
parsed_line = res_callback
227+
else:
228+
if options["debug"]:
229+
print(
230+
"CallBack force at False and callBack result is not correct")
231+
else:
232+
parsed_line = res_callback
233+
final_json.append(parsed_line)
234+
return final_json
235+
converted = reader(line_reader)
236+
if isinstance(path_to_file, str):
237+
csv_file.close()
238+
return converted

0 commit comments

Comments
 (0)