Skip to content

Commit 4daff1f

Browse files
committed
fix(wiki_tools): return list of result dicts for semantic_search return_json
semantic_search with SearchParam.return_json=True previously fed the raw SMW ask result dicts into the flat-list comprehension, so iterating each dict yielded its keys and the call returned a useless list like ['query'] instead of the result data. Skip the flatten when return_json=True and return the list of raw result dicts (one per query, always a list even for a single query). The default return_json=False behavior (flat list of page-title fulltext strings) is unchanged. Add unit tests covering return_json=True for a single query and a list of queries, plus return_json=False still returning a flat list of titles.
1 parent 7191678 commit 4daff1f

2 files changed

Lines changed: 94 additions & 17 deletions

File tree

‎src/osw/wiki_tools.py‎

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,10 @@ def semantic_search(
221221
222222
Returns
223223
-------
224-
page_list:
225-
List of page titles
224+
result:
225+
With ``return_json=False`` (default): a flat list of page-title fulltext
226+
strings. With ``return_json=True``: a list of raw SMW ``ask`` result dicts,
227+
one per query (always a list, even for a single query).
226228
"""
227229
if not isinstance(query, SearchParam):
228230
query = SearchParam(query=query)
@@ -231,27 +233,26 @@ def semantic_search_(single_query):
231233
page_list = list()
232234
single_query += f"|limit={query.limit}"
233235
result = site.api("ask", query=single_query, format="json")
234-
if len(result["query"]["results"]) == 0:
235-
if query.debug:
236+
if query.debug:
237+
if len(result["query"]["results"]) == 0:
236238
print("Query '{}' returned no results".format(single_query))
237-
else:
238-
if query.debug:
239+
else:
239240
print(
240241
"Query '{}' returned {} results".format(
241242
single_query, len(result["query"]["results"])
242243
)
243244
)
244-
if query.return_json:
245-
return result
246-
247-
for page in result["query"]["results"].values():
248-
title = page["fulltext"]
249-
exists = page["exists"]
250-
if "#" not in title and query.debug:
251-
print(title)
252-
# original position of "page_list.append(title)" line
253-
if exists == "1":
254-
page_list.append(title)
245+
if query.return_json:
246+
return result
247+
248+
for page in result["query"]["results"].values():
249+
title = page["fulltext"]
250+
exists = page["exists"]
251+
if "#" not in title and query.debug:
252+
print(title)
253+
# original position of "page_list.append(title)" line
254+
if exists == "1":
255+
page_list.append(title)
255256
return page_list
256257

257258
if query.parallel:
@@ -261,6 +262,12 @@ def semantic_search_(single_query):
261262
else:
262263
query_results = [semantic_search_(single_query=sq) for sq in query.query]
263264

265+
if query.return_json:
266+
# Each entry of query_results is the raw SMW result dict for one query.
267+
# Do not flatten dicts; always return the list of result dicts (one per
268+
# query), even when only a single query was passed.
269+
return query_results
270+
264271
return [item for sublist in query_results for item in sublist]
265272
# todo: @Simon: a list of lists of strings (sublist for each query in query list)
266273
# or a list of strings (results of all queries combined)?

‎tests/test_wiki_tools.py‎

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from unittest.mock import MagicMock
2+
13
import osw.wiki_tools as wt
24

35

@@ -6,3 +8,71 @@ def test_create_flat_content_structure_from_wikitext():
68
expected = [{"Template": {"param": ["value"]}}]
79
result = wt.create_flat_content_structure_from_wikitext(wikitext)
810
assert result == expected
11+
12+
13+
def _ask_result(*titles):
14+
"""Build a minimal SMW ``ask`` API result dict for the given page titles."""
15+
return {
16+
"query": {
17+
"results": {
18+
title: {
19+
"fulltext": title,
20+
"fullurl": f"https://example.org/wiki/{title}",
21+
"namespace": 0,
22+
"exists": "1",
23+
"displaytitle": "",
24+
"printouts": {"SomeProperty": [f"{title}-value"]},
25+
}
26+
for title in titles
27+
}
28+
}
29+
}
30+
31+
32+
def test_semantic_search_return_json_single_query_returns_list_with_dict():
33+
result = _ask_result("Item:OSW1")
34+
site = MagicMock()
35+
site.api.return_value = result
36+
37+
out = wt.semantic_search(
38+
site, wt.SearchParam(query="[[HasType::Category:Item]]", return_json=True)
39+
)
40+
41+
# A single query still returns a list (of one raw result dict), not a bare dict
42+
# and not a flattened list of keys
43+
assert isinstance(out, list)
44+
assert out == [result]
45+
# printouts must be preserved intact
46+
assert out[0]["query"]["results"]["Item:OSW1"]["printouts"] == {
47+
"SomeProperty": ["Item:OSW1-value"]
48+
}
49+
50+
51+
def test_semantic_search_return_json_list_returns_list_of_dicts():
52+
result_a = _ask_result("Item:OSW1")
53+
result_b = _ask_result("Item:OSW2")
54+
site = MagicMock()
55+
site.api.side_effect = [result_a, result_b]
56+
57+
out = wt.semantic_search(
58+
site,
59+
wt.SearchParam(
60+
query=["[[HasType::Category:Item]]", "[[HasType::Category:Person]]"],
61+
return_json=True,
62+
),
63+
)
64+
65+
# A list of queries must return a list of result dicts, one per query
66+
assert isinstance(out, list)
67+
assert out == [result_a, result_b]
68+
69+
70+
def test_semantic_search_returns_flat_list_of_titles():
71+
result = _ask_result("Item:OSW1", "Item:OSW2")
72+
site = MagicMock()
73+
site.api.return_value = result
74+
75+
out = wt.semantic_search(site, "[[HasType::Category:Item]]")
76+
77+
# return_json=False (the default) still yields a flat list of page titles
78+
assert out == ["Item:OSW1", "Item:OSW2"]

0 commit comments

Comments
 (0)