Spaces:
Running
Running
File size: 7,318 Bytes
5796881 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | """Unit tests for ops.py's pure JSON-walking helpers.
OPS's XML-to-JSON conversion is the trickiest part of this module: text
nodes become {"$": "..."}, attributes become "@name" keys, and a repeated
XML element becomes a list *unless there's only one*, in which case it stays
a bare dict. Every helper here has to handle both shapes; these tests pin
both for each one.
"""
import pytest
from ops import (
_as_list,
_text,
_pick_lang,
_epodoc_number,
_extract_title,
_extract_abstract,
_extract_classifications,
_fulltext_paragraphs,
_to_cql,
_normalize_epodoc,
)
class TestAsList:
def test_none_becomes_empty_list(self):
assert _as_list(None) == []
def test_single_dict_is_wrapped(self):
assert _as_list({"a": 1}) == [{"a": 1}]
def test_list_passes_through_unchanged(self):
assert _as_list([{"a": 1}, {"a": 2}]) == [{"a": 1}, {"a": 2}]
class TestText:
def test_extracts_dollar_key(self):
assert _text({"$": "hello"}) == "hello"
def test_plain_string_passes_through(self):
assert _text("hello") == "hello"
def test_none_for_anything_else(self):
assert _text(None) is None
assert _text({"@lang": "en"}) is None
class TestPickLang:
def test_picks_requested_language_from_list(self):
nodes = [{"@lang": "de", "$": "Hallo"}, {"@lang": "en", "$": "Hello"}]
assert _pick_lang(nodes) == {"@lang": "en", "$": "Hello"}
def test_falls_back_to_first_when_language_missing(self):
nodes = [{"@lang": "de", "$": "Hallo"}, {"@lang": "fr", "$": "Bonjour"}]
assert _pick_lang(nodes) == {"@lang": "de", "$": "Hallo"}
def test_single_dict_not_wrapped_in_a_list_still_works(self):
node = {"@lang": "en", "$": "Hello"}
assert _pick_lang(node) == node
def test_empty_input_returns_none(self):
assert _pick_lang(None) is None
assert _pick_lang([]) is None
class TestEpodocNumber:
def test_prefers_the_epodoc_document_id(self):
exchange_doc = {
"@country": "US",
"@doc-number": "11930446",
"bibliographic-data": {
"publication-reference": {
"document-id": [
{"@document-id-type": "docdb", "doc-number": {"$": "11930446"}},
{"@document-id-type": "epodoc", "doc-number": {"$": "US11930446"}},
]
}
},
}
assert _epodoc_number(exchange_doc) == "US11930446"
def test_falls_back_to_country_plus_doc_number(self):
exchange_doc = {"@country": "US", "@doc-number": "11930446", "bibliographic-data": {}}
assert _epodoc_number(exchange_doc) == "US11930446"
def test_none_when_nothing_available(self):
assert _epodoc_number({"bibliographic-data": {}}) is None
class TestExtractTitle:
def test_from_a_list_of_languages(self):
bd = {"invention-title": [{"@lang": "en", "$": "Widget"}, {"@lang": "de", "$": "Widget-DE"}]}
assert _extract_title(bd) == "Widget"
def test_from_a_single_bare_dict(self):
bd = {"invention-title": {"@lang": "en", "$": "Widget"}}
assert _extract_title(bd) == "Widget"
def test_none_when_missing(self):
assert _extract_title({}) is None
class TestExtractAbstract:
def test_joins_paragraphs_from_a_list(self):
doc = {"abstract": [{"@lang": "en", "p": [{"$": "Part one."}, {"$": "Part two."}]}]}
assert _extract_abstract(doc) == "Part one. Part two."
def test_single_paragraph_not_wrapped_in_a_list(self):
doc = {"abstract": {"@lang": "en", "p": {"$": "Only paragraph."}}}
assert _extract_abstract(doc) == "Only paragraph."
def test_none_when_missing(self):
assert _extract_abstract({}) is None
class TestExtractClassifications:
def test_builds_codes_from_the_five_part_symbol(self):
bd = {
"patent-classifications": {
"patent-classification": [
{
"section": {"$": "G"},
"class": {"$": "06"},
"subclass": {"$": "F"},
"main-group": {"$": "17"},
"subgroup": {"$": "30"},
}
]
}
}
codes = _extract_classifications(bd)
assert len(codes) == 1
assert codes[0].code == "G06F17/30"
assert codes[0].description == ""
def test_dedupes_and_skips_incomplete_entries(self):
bd = {
"patent-classifications": {
"patent-classification": [
{"section": {"$": "G"}, "class": {"$": "06"}, "subclass": {"$": "F"}, "main-group": {"$": "17"}, "subgroup": {"$": "30"}},
{"section": {"$": "G"}, "class": {"$": "06"}, "subclass": {"$": "F"}, "main-group": {"$": "17"}, "subgroup": {"$": "30"}},
{"section": {"$": "H"}}, # incomplete - no class/subclass/main-group
]
}
}
codes = _extract_classifications(bd)
assert [c.code for c in codes] == ["G06F17/30"]
def test_none_when_no_classifications(self):
assert _extract_classifications({}) is None
class TestFulltextParagraphs:
def test_claims_join_claim_text_lines(self):
data = {
"ops:world-patent-data": {
"ftxt:fulltext-documents": {
"ftxt:fulltext-document": {
"claims": {
"@lang": "en",
"claim": [
{"claim-text": {"$": "1. A widget."}},
{"claim-text": [{"$": "2. A gadget,"}, {"$": "further comprising a mechanism."}]},
],
}
}
}
}
}
assert _fulltext_paragraphs(data, "claims") == (
"1. A widget.\n2. A gadget,\nfurther comprising a mechanism."
)
def test_description_joins_paragraphs(self):
data = {
"ops:world-patent-data": {
"ftxt:fulltext-documents": {
"ftxt:fulltext-document": {
"description": {"@lang": "en", "p": [{"$": "Para one."}, {"$": "Para two."}]}
}
}
}
}
assert _fulltext_paragraphs(data, "description") == "Para one.\nPara two."
def test_none_when_document_missing(self):
assert _fulltext_paragraphs({"ops:world-patent-data": {}}, "claims") is None
@pytest.mark.parametrize(
"raw, expected",
[
("widget", 'txt all "widget"'),
("agentic ai", 'txt all "agentic ai"'),
('pn = "US1234"', 'pn = "US1234"'),
("", ""),
('has "quotes"', 'txt all "has quotes"'),
],
)
def test_to_cql(raw, expected):
assert _to_cql(raw) == expected
@pytest.mark.parametrize(
"raw, expected",
[
("US11930446B2", "US11930446"),
("EP4760514A1", "EP4760514"),
("US 11930446 B2", "US11930446"),
("US11930446", "US11930446"),
],
)
def test_normalize_epodoc(raw, expected):
assert _normalize_epodoc(raw) == expected
|