@@ -84,14 +84,24 @@ def find_Ftype_and_colH(item, row_data, response_options):
8484
8585 return row_data
8686
87- def process_item (item , item_properties , activity_name , activity_preamble , contextfile , http_kwargs , compute_item = False , compute_expr = None ):
87+
88+ def process_item (
89+ item ,
90+ item_properties ,
91+ activity_name ,
92+ activity_preamble ,
93+ contextfile ,
94+ http_kwargs ,
95+ compute_item = False ,
96+ compute_expr = None ,
97+ ):
8898 """
8999 Process an item in JSON format and extract relevant information into a dictionary.
90100 Only includes non-empty/non-None values to match clean_dict_nans behavior.
91101 """
92102 if activity_name .endswith ("_schema" ):
93103 activity_name = activity_name [:- 7 ]
94-
104+
95105 # Initialize with only required fields
96106 row_data = {
97107 "var_name" : item .id ,
@@ -112,7 +122,9 @@ def process_item(item, item_properties, activity_name, activity_preamble, contex
112122 if "ResponseOption" in resp ["category" ]:
113123 response_options = ResponseOption (** resp )
114124 else :
115- raise Exception (f"Expected to have ResponseOption but got { resp ['category' ]} " )
125+ raise Exception (
126+ f"Expected to have ResponseOption but got { resp ['category' ]} "
127+ )
116128 else :
117129 response_options = item .responseOptions
118130
@@ -122,19 +134,27 @@ def process_item(item, item_properties, activity_name, activity_preamble, contex
122134 row_data ["val_min" ] = response_options .minValue
123135 if response_options .maxValue is not None :
124136 row_data ["val_max" ] = response_options .maxValue
125-
137+
126138 # Handle choices
127139 choices = response_options .choices
128140 if choices and not isinstance (choices , str ):
129141 if isinstance (choices , list ):
130- item_choices = [f"{ ch .value } , { ch .name .get ('en' , '' )} " for ch in choices if ch .value is not None ]
142+ item_choices = [
143+ f"{ ch .value } , { ch .name .get ('en' , '' )} "
144+ for ch in choices
145+ if ch .value is not None
146+ ]
131147 if item_choices :
132148 row_data ["choices" ] = " | " .join (item_choices )
133149
134150 # Add valueRequired if explicitly True
135- if item_properties and "valueRequired" in item_properties and item_properties ["valueRequired" ] is True :
151+ if (
152+ item_properties
153+ and "valueRequired" in item_properties
154+ and item_properties ["valueRequired" ] is True
155+ ):
136156 row_data ["required" ] = "y"
137-
157+
138158 var_name = str (item .id ).split ("/" )[- 1 ] # Get the last part of the id path
139159 if var_name .endswith ("_total_score" ):
140160 row_data ["isVis_logic" ] = False # This will make the field hidden
@@ -143,7 +163,11 @@ def process_item(item, item_properties, activity_name, activity_preamble, contex
143163 row_data ["isVis_logic" ] = item_properties ["isVis" ]
144164
145165 # Handle description
146- if item .description and "en" in item .description and item .description ["en" ]:
166+ if (
167+ item .description
168+ and "en" in item .description
169+ and item .description ["en" ]
170+ ):
147171 row_data ["field_notes" ] = item .description ["en" ]
148172
149173 # Handle preamble
@@ -227,11 +251,13 @@ def get_csv_data(dir_path, contextfile, http_kwargs):
227251
228252 # Get activity name without adding extra _schema
229253 activity_name = act .id .split ("/" )[- 1 ]
230- if activity_name .endswith ('_schema.jsonld' ):
231- activity_name = activity_name [:- 12 ] # Remove _schema.jsonld
232- elif activity_name .endswith ('.jsonld' ):
254+ if activity_name .endswith ("_schema.jsonld" ):
255+ activity_name = activity_name [
256+ :- 12
257+ ] # Remove _schema.jsonld
258+ elif activity_name .endswith (".jsonld" ):
233259 activity_name = activity_name [:- 7 ] # Remove .jsonld
234-
260+
235261 items_properties .update (
236262 {
237263 el ["isAbout" ]: el
@@ -245,22 +271,30 @@ def get_csv_data(dir_path, contextfile, http_kwargs):
245271 item_order = [("ord" , el ) for el in act .ui .order ]
246272 item_calc = [("calc" , el ) for el in act .compute ]
247273
248- computed_fields = {calc_item .variableName for _ , calc_item in item_calc }
249-
274+ computed_fields = {
275+ calc_item .variableName
276+ for _ , calc_item in item_calc
277+ }
250278
251279 for tp , item in item_order + item_calc :
252280 try :
253281 if tp == "calc" :
254282 js_expr = item .jsExpression
255283 var_name = item .variableName
256-
284+
257285 # Find the corresponding item properties
258286 if var_name in items_properties :
259- item = items_properties [var_name ]["isAbout" ]
287+ item = items_properties [var_name ][
288+ "isAbout"
289+ ]
260290 # Ensure computed fields are marked as hidden
261- items_properties [var_name ]["isVis" ] = False
291+ items_properties [var_name ][
292+ "isVis"
293+ ] = False
262294 else :
263- print (f"WARNING: no item properties found for computed field { var_name } in { activity_name } " )
295+ print (
296+ f"WARNING: no item properties found for computed field { var_name } in { activity_name } "
297+ )
264298 continue
265299 item_calc = True
266300 else :
@@ -269,7 +303,7 @@ def get_csv_data(dir_path, contextfile, http_kwargs):
269303 it_prop = items_properties .get (item )
270304 if not _is_url (item ):
271305 item = Path (activity_path ).parent / item
272-
306+
273307 try :
274308 item_json = load_file (
275309 item ,
@@ -285,9 +319,15 @@ def get_csv_data(dir_path, contextfile, http_kwargs):
285319 print (f"Error loading item: { item } " )
286320 print (f"Error details: { str (e )} " )
287321 continue
288-
289- activity_name = act .id .split ("/" )[- 1 ].split ("." )[0 ]
290- activity_preamble = act .preamble .get ("en" , "" ).strip () if hasattr (act , 'preamble' ) else ""
322+
323+ activity_name = act .id .split ("/" )[- 1 ].split (
324+ "."
325+ )[0 ]
326+ activity_preamble = (
327+ act .preamble .get ("en" , "" ).strip ()
328+ if hasattr (act , "preamble" )
329+ else ""
330+ )
291331
292332 row_data = process_item (
293333 itm ,
@@ -302,12 +342,15 @@ def get_csv_data(dir_path, contextfile, http_kwargs):
302342 csv_data .append (row_data )
303343
304344 except Exception as e :
305- print (f"Error processing item { item } : { str (e )} " )
345+ print (
346+ f"Error processing item { item } : { str (e )} "
347+ )
306348 continue
307349 # Break after finding the first _schema file
308350 break
309351 return csv_data
310352
353+
311354def write_to_csv (csv_data , output_csv_filename ):
312355 # REDCap-specific headers
313356 headers = [
@@ -328,23 +371,25 @@ def write_to_csv(csv_data, output_csv_filename):
328371 "Question Number (surveys only)" ,
329372 "Matrix Group Name" ,
330373 "Matrix Ranking?" ,
331- "Field Annotation"
374+ "Field Annotation" ,
332375 ]
333376
334377 # Writing to the CSV file
335- with open (output_csv_filename , "w" , newline = "" , encoding = "utf-8" ) as csvfile :
378+ with open (
379+ output_csv_filename , "w" , newline = "" , encoding = "utf-8"
380+ ) as csvfile :
336381 writer = csv .DictWriter (csvfile , fieldnames = headers )
337382 writer .writeheader ()
338-
383+
339384 for row in csv_data :
340385 redcap_row = {}
341-
386+
342387 # Handle var_name URL conversion
343388 var_name = row ["var_name" ]
344389 if _is_url (var_name ):
345390 var_name = var_name .split ("/" )[- 1 ].split ("." )[0 ]
346391 redcap_row ["Variable / Field Name" ] = var_name
347-
392+
348393 # Handle form name
349394 activity_name = row ["activity" ]
350395 if activity_name .endswith ("_schema" ):
@@ -365,15 +410,21 @@ def write_to_csv(csv_data, output_csv_filename):
365410 "isVis_logic" : "Branching Logic (Show field only if...)" ,
366411 "field_annotation" : "Field Annotation" ,
367412 "matrix_group" : "Matrix Group Name" ,
368- "matrix_ranking" : "Matrix Ranking?"
413+ "matrix_ranking" : "Matrix Ranking?" ,
369414 }
370415
371416 # Add mapped fields only if they exist and aren't empty
372417 for src_key , dest_key in field_mappings .items ():
373- if src_key in row and row [src_key ] is not None and row [src_key ] != "" :
418+ if (
419+ src_key in row
420+ and row [src_key ] is not None
421+ and row [src_key ] != ""
422+ ):
374423 # Special handling for visibility logic
375424 if src_key == "isVis_logic" :
376- if row [src_key ] is not True : # Only add if not default True
425+ if (
426+ row [src_key ] is not True
427+ ): # Only add if not default True
377428 redcap_row [dest_key ] = row [src_key ]
378429 # Special handling for required field
379430 elif src_key == "required" :
@@ -382,7 +433,9 @@ def write_to_csv(csv_data, output_csv_filename):
382433 elif src_key == "field_annotation" :
383434 current_annotation = redcap_row .get (dest_key , "" )
384435 if current_annotation :
385- redcap_row [dest_key ] = f"{ current_annotation } { row [src_key ]} "
436+ redcap_row [dest_key ] = (
437+ f"{ current_annotation } { row [src_key ]} "
438+ )
386439 else :
387440 redcap_row [dest_key ] = row [src_key ]
388441 else :
@@ -392,6 +445,7 @@ def write_to_csv(csv_data, output_csv_filename):
392445
393446 print ("The CSV file was written successfully" )
394447
448+
395449def reproschema2redcap (input_dir_path , output_csv_filename ):
396450 contextfile = CONTEXTFILE_URL # todo, give an option
397451 http_kwargs = {}
0 commit comments