@@ -205,7 +205,7 @@ def generate_biosphere_mapping(
205
205
output_directory : Optional [Path ] = None ,
206
206
output_version : str = "3.0.0" ,
207
207
description : Optional [str ] = None ,
208
- ) -> Path :
208
+ ) -> Optional [ Path ] :
209
209
"""Generate a Randonneur mapping file for biosphere edge attributes from source to target."""
210
210
configure_logs (write_logs = write_logs )
211
211
@@ -246,23 +246,52 @@ def generate_biosphere_mapping(
246
246
description = f"Data migration file from { source_db_name } to { target_db_name } generated with `ecoinvent_migrate` version { __version__ } "
247
247
248
248
if not missing_sheet :
249
- data = pd .read_excel (io = excel_filepath , sheet_name = candidates [0 ]).to_dict (orient = "records" )
250
- data = source_target_biosphere_pair (
251
- data = data ,
252
- source_version = source_version ,
253
- target_version = target_version ,
254
- keep_deletions = keep_deletions ,
255
- )
256
- affected_uuids = {
257
- o ["source" ]["uuid" ]
258
- for o in itertools .chain (data .get ("replace" , []), data .get ("delete" , []))
259
- }
260
- data = supplement_biosphere_changes_with_real_data_comparison (
261
- data = data ,
262
- affected_uuids = affected_uuids ,
263
- source_version = source_version ,
264
- target_version = target_version ,
265
- )
249
+ # Try reading the sheet
250
+ df = pd .read_excel (io = excel_filepath , sheet_name = candidates [0 ])
251
+
252
+ # Handle the multi-index case
253
+ if df .columns [0 ].startswith ("**" ):
254
+ logger .debug ("Detected multi-index format, adjusting reading parameters" )
255
+ df = pd .read_excel (io = excel_filepath , sheet_name = candidates [0 ], skiprows = 1 )
256
+
257
+ # Handle the new format case
258
+ if "deleted exchanges" in df .columns :
259
+ logger .debug ("Detected new exchange format, adjusting data structure" )
260
+ # Get the actual column headers from the first row
261
+ new_headers = {col : val for col , val in df .iloc [0 ].items () if isinstance (val , str )}
262
+ df = df .rename (columns = new_headers ).iloc [1 :]
263
+
264
+ if df .empty :
265
+ logger .info (
266
+ "EE Deletions sheet is empty in change report for {source_v} to {target_v}. This likely means no biosphere changes." ,
267
+ source_v = source_version ,
268
+ target_v = target_version ,
269
+ )
270
+ data = {"delete" : [], "replace" : []}
271
+ else :
272
+ data = df .to_dict (orient = "records" )
273
+ data = source_target_biosphere_pair (
274
+ data = data ,
275
+ source_version = source_version ,
276
+ target_version = target_version ,
277
+ keep_deletions = keep_deletions ,
278
+ )
279
+ # Ensure both keys exist
280
+ if "delete" not in data :
281
+ data ["delete" ] = []
282
+ if "replace" not in data :
283
+ data ["replace" ] = []
284
+
285
+ affected_uuids = {
286
+ o ["source" ]["uuid" ]
287
+ for o in itertools .chain (data .get ("replace" , []), data .get ("delete" , []))
288
+ }
289
+ data = supplement_biosphere_changes_with_real_data_comparison (
290
+ data = data ,
291
+ affected_uuids = affected_uuids ,
292
+ source_version = source_version ,
293
+ target_version = target_version ,
294
+ )
266
295
else :
267
296
data = supplement_biosphere_changes_with_real_data_comparison (
268
297
data = {"delete" : [], "replace" : []},
@@ -271,16 +300,28 @@ def generate_biosphere_mapping(
271
300
target_version = target_version ,
272
301
)
273
302
274
- if not data ["delete" ] and not data ["replace" ]:
275
- logger .info ("It seems like there are no biosphere changes for this release. Doing nothing." )
276
- return
303
+ # Ensure we have non-empty data before creating Datapackage
304
+ has_data = False
305
+ cleaned_data = {}
306
+ for key in ["delete" , "replace" ]:
307
+ if data .get (key ) and len (data [key ]) > 0 :
308
+ cleaned_data [key ] = data [key ]
309
+ has_data = True
310
+
311
+ if not has_data :
312
+ logger .info ("No valid biosphere changes found after processing. Doing nothing." )
313
+ return None
277
314
278
315
dp = Datapackage (
279
316
name = f"{ source_db_name } -{ target_db_name } " ,
280
317
description = description ,
281
318
contributors = [
282
- {"title" : "ecoinvent association" , "path" : "https://ecoinvent.org/" , "roles" : ["author" ]},
283
- {"title" : "Chris Mutel" , "path" : "https://chris.mutel.org/" , "roles" : ["wrangler" ]},
319
+ {
320
+ "title" : "ecoinvent association" ,
321
+ "path" : "https://ecoinvent.org/" ,
322
+ "role" : "author" ,
323
+ },
324
+ {"title" : "Chris Mutel" , "path" : "https://chris.mutel.org/" , "role" : "wrangler" },
284
325
],
285
326
mapping_source = MappingConstants .ECOSPOLD2_BIO ,
286
327
mapping_target = MappingConstants .ECOSPOLD2_BIO ,
@@ -290,7 +331,9 @@ def generate_biosphere_mapping(
290
331
target_id = target_db_name ,
291
332
licenses = licenses ,
292
333
)
293
- for key , value in data .items ():
334
+
335
+ # Only add non-empty data sections
336
+ for key , value in cleaned_data .items ():
294
337
dp .add_data (key , value )
295
338
296
339
if write_file :
0 commit comments