Skip to content

Commit 69fcdd4

Browse files
committed
Add collapse_comments option and extract includedActivities fields in ecospold2 extractor
- New `collapse_comments` kwarg (default True) on `extract()` and `extract_activity()`; when False, `comment` is a dict keyed by source field instead of a flat string - Always extract `included_activities_start` and `included_activities_end` as top-level dataset fields from activityDescription/activity - Fix pre-existing double-space in collapsed comment separator (": " not ": ") - Update existing tests for new fields and corrected spacing; add test for dict mode
1 parent 859ec81 commit 69fcdd4

2 files changed

Lines changed: 90 additions & 42 deletions

File tree

bw2io/extractors/ecospold2.py

Lines changed: 68 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ def extract(
113113
db_name: str,
114114
use_mp: bool = True,
115115
cache: bool = False,
116+
collapse_comments: bool = True,
116117
):
117118
"""
118119
Extract data from all ecospold2 files in a directory.
@@ -128,6 +129,11 @@ def extract(
128129
cache : bool, optional
129130
Cache extracted datasets as `.json.gz` files alongside the source `.spold`
130131
files for faster re-imports (default is False).
132+
collapse_comments : bool, optional
133+
If True (default), combine all comment fields into a single string. If False,
134+
return ``comment`` as a dict with keys ``general``, ``included activities
135+
start``, ``included activities end``, ``geography``, ``technology``, and
136+
``time period`` (only non-empty keys are included).
131137
132138
Returns
133139
-------
@@ -168,7 +174,7 @@ def extract(
168174
pool.apply_async(
169175
Ecospold2DataExtractor.extract_activity,
170176
args=(dirpath, x, db_name),
171-
kwds={"cache": cache},
177+
kwds={"cache": cache, "collapse_comments": collapse_comments},
172178
callback=lambda _: pb.update(1),
173179
)
174180
for x in filelist
@@ -177,7 +183,11 @@ def extract(
177183
else:
178184
data = []
179185
for filename in tqdm(filelist):
180-
data.append(cls.extract_activity(dirpath, filename, db_name, cache=cache))
186+
data.append(
187+
cls.extract_activity(
188+
dirpath, filename, db_name, cache=cache, collapse_comments=collapse_comments
189+
)
190+
)
181191

182192
return data
183193

@@ -218,7 +228,7 @@ def condense_multiline_comment(cls, element):
218228
return ""
219229

220230
@classmethod
221-
def extract_activity(cls, dirpath, filename, db_name, cache: bool = False):
231+
def extract_activity(cls, dirpath, filename, db_name, cache: bool = False, collapse_comments: bool = True):
222232
"""
223233
Extract and return the data of an activity from an XML file with the given
224234
`filename` in the directory with the path `dirpath`.
@@ -268,44 +278,60 @@ def extract_activity(cls, dirpath, filename, db_name, cache: bool = False):
268278
else:
269279
stem = root.childActivityDataset
270280

271-
comments = [
272-
cls.condense_multiline_comment(
273-
getattr2(stem.activityDescription.activity, "generalComment")
274-
),
275-
(
276-
"Included activities start: ",
277-
getattr2(stem.activityDescription.activity, "includedActivitiesStart"),
278-
),
279-
(
280-
"Included activities end: ",
281-
getattr2(stem.activityDescription.activity, "includedActivitiesEnd"),
282-
),
283-
(
284-
"Geography: ",
285-
cls.condense_multiline_comment(
286-
getattr2(stem.activityDescription.geography, "comment")
287-
),
288-
),
289-
(
290-
"Technology: ",
291-
cls.condense_multiline_comment(
292-
getattr2(stem.activityDescription.technology, "comment")
293-
),
294-
),
295-
(
296-
"Time period: ",
297-
cls.condense_multiline_comment(
298-
getattr2(stem.activityDescription.timePeriod, "comment")
299-
),
300-
),
301-
]
302-
comment = "\n".join(
303-
[
304-
(" ".join(str(i) for i in x) if isinstance(x, tuple) else x)
305-
for x in comments
306-
if (x[1] if isinstance(x, tuple) else x)
307-
]
281+
def _text(obj):
282+
if isinstance(obj, dict):
283+
return ""
284+
try:
285+
return obj.text or ""
286+
except Exception:
287+
return ""
288+
289+
general_comment = cls.condense_multiline_comment(
290+
getattr2(stem.activityDescription.activity, "generalComment")
291+
)
292+
included_start = _text(
293+
getattr2(stem.activityDescription.activity, "includedActivitiesStart")
294+
)
295+
included_end = _text(
296+
getattr2(stem.activityDescription.activity, "includedActivitiesEnd")
297+
)
298+
geo_comment = cls.condense_multiline_comment(
299+
getattr2(stem.activityDescription.geography, "comment")
308300
)
301+
tech_comment = cls.condense_multiline_comment(
302+
getattr2(stem.activityDescription.technology, "comment")
303+
)
304+
time_comment = cls.condense_multiline_comment(
305+
getattr2(stem.activityDescription.timePeriod, "comment")
306+
)
307+
308+
if collapse_comments:
309+
parts = [general_comment]
310+
if included_start:
311+
parts.append("Included activities start: " + included_start)
312+
if included_end:
313+
parts.append("Included activities end: " + included_end)
314+
if geo_comment:
315+
parts.append("Geography: " + geo_comment)
316+
if tech_comment:
317+
parts.append("Technology: " + tech_comment)
318+
if time_comment:
319+
parts.append("Time period: " + time_comment)
320+
comment = "\n".join(x for x in parts if x)
321+
else:
322+
comment = {}
323+
if general_comment:
324+
comment["general"] = general_comment
325+
if included_start:
326+
comment["included activities start"] = included_start
327+
if included_end:
328+
comment["included activities end"] = included_end
329+
if geo_comment:
330+
comment["geography"] = geo_comment
331+
if tech_comment:
332+
comment["technology"] = tech_comment
333+
if time_comment:
334+
comment["time period"] = time_comment
309335

310336
classifications = [
311337
(el.classificationSystem.text, el.classificationValue.text)
@@ -315,6 +341,8 @@ def extract_activity(cls, dirpath, filename, db_name, cache: bool = False):
315341

316342
data = {
317343
"comment": comment,
344+
"included_activities_start": included_start,
345+
"included_activities_end": included_end,
318346
"classifications": classifications,
319347
"activity type": ACTIVITY_TYPES[
320348
int(stem.activityDescription.activity.get("specialActivityType") or 0)

tests/ecospold2/ecospold2_extractor.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ def test_extraction_without_synonyms():
1818
"ei",
1919
)
2020
expected = {
21-
"comment": "Things and stuff and whatnot\na Kikki comment\nIncluded activities start: Includes start stuff\nIncluded activities end: Includes end stuff\nTechnology: typical technology for ze Germans!",
21+
"comment": "Things and stuff and whatnot\na Kikki comment\nIncluded activities start: Includes start stuff\nIncluded activities end: Includes end stuff\nTechnology: typical technology for ze Germans!",
22+
"included_activities_start": "Includes start stuff",
23+
"included_activities_end": "Includes end stuff",
2224
"classifications": [
2325
("EcoSpold01Categories", "construction materials/concrete"),
2426
(
@@ -157,7 +159,9 @@ def test_extraction_with_synonyms():
157159
"ei",
158160
)
159161
expected = {
160-
"comment": "Things and stuff and whatnot\na Kikki comment\nIncluded activities end: Includes some stuff\nTechnology: typical technology for ze Germans!",
162+
"comment": "Things and stuff and whatnot\na Kikki comment\nIncluded activities end: Includes some stuff\nTechnology: typical technology for ze Germans!",
163+
"included_activities_start": "",
164+
"included_activities_end": "Includes some stuff",
161165
"classifications": [
162166
("EcoSpold01Categories", "construction materials/concrete"),
163167
(
@@ -366,3 +370,19 @@ def test_cache_written_and_read(tmp_path):
366370

367371
cached = Ecospold2DataExtractor.extract_activity(tmp_path, SPOLD, "ei", cache=True)
368372
assert cached == {"name": "from cache"}
373+
374+
375+
def test_collapse_comments_false():
376+
data = Ecospold2DataExtractor.extract(
377+
FIXTURES / SPOLD,
378+
"ei",
379+
collapse_comments=False,
380+
)
381+
comment = data[0]["comment"]
382+
assert isinstance(comment, dict)
383+
assert comment["general"] == "Things and stuff and whatnot\na Kikki comment"
384+
assert comment["included activities start"] == "Includes start stuff"
385+
assert comment["included activities end"] == "Includes end stuff"
386+
assert comment["technology"] == "typical technology for ze Germans!"
387+
assert "geography" not in comment
388+
assert "time period" not in comment

0 commit comments

Comments
 (0)