Coverage for test / conftest.py: 94%
228 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-25 18:06 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-25 18:06 +0000
1# SPDX-FileCopyrightText: 2024 Elia Rizzetto <elia.rizzetto2@unibo.it>
2# SPDX-FileCopyrightText: 2026 Arcangelo Massari <arcangelo.massari@unibo.it>
3#
4# SPDX-License-Identifier: ISC
6import json as json_module
7import re
8from urllib.parse import unquote
10import pytest
11import responses
13from oc_ds_converter.oc_idmanager.oc_data_storage.in_memory_manager import InMemoryStorageManager
14from oc_ds_converter.oc_idmanager.oc_data_storage.redis_manager import RedisStorageManager
15from oc_ds_converter.oc_idmanager.oc_data_storage.sqlite_manager import SqliteStorageManager
18@pytest.fixture(params=["redis", "sqlite", "inmemory"])
19def storage_manager(request: pytest.FixtureRequest, tmp_path):
20 if request.param == "redis":
21 sm = RedisStorageManager(testing=True)
22 elif request.param == "sqlite":
23 sm = SqliteStorageManager(str(tmp_path / "test.db"))
24 else:
25 sm = InMemoryStorageManager(str(tmp_path / "test.json"))
26 yield sm
27 sm.delete_storage()
30@pytest.fixture(autouse=True)
31def mock_http_requests(request):
32 with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps:
33 _register_doi_ra_mocks(rsps)
34 _register_doi_mocks(rsps)
35 _register_crossref_mocks(rsps)
36 _register_arxiv_mocks(rsps)
37 _register_pmid_mocks(rsps)
38 _register_orcid_mocks(rsps)
39 _register_openalex_mocks(rsps)
40 _register_pmc_mocks(rsps)
41 _register_datacite_mocks(rsps)
42 _register_jid_mocks(rsps)
43 _register_ror_mocks(rsps)
44 _register_viaf_mocks(rsps)
45 _register_wikidata_mocks(rsps)
46 _register_wikipedia_mocks(rsps)
47 _register_medra_mocks(rsps)
48 _register_url_mocks(rsps)
49 yield rsps
52def _register_doi_ra_mocks(rsps: responses.RequestsMock) -> None:
53 def doi_ra_callback(request):
54 return (200, {}, json_module.dumps([{"RA": "Crossref"}]))
56 rsps.add_callback(
57 responses.GET,
58 re.compile(r"https://doi\.org/ra/.*"),
59 callback=doi_ra_callback,
60 content_type="application/json",
61 )
64def _register_doi_mocks(rsps: responses.RequestsMock) -> None:
65 valid_dois = {
66 "10.1108/jd-12-2013-0166",
67 "10.1130/2015.2513(00)",
68 "10.1007/s11192-022-04367-w",
69 "10.1007/s12160-011-9282-0",
70 "10.5281/zenodo.4725899",
71 "10.2307/3053861",
72 "10.1016/0006-2944(75)90147-7",
73 "10.1016/0006-291x(75)90482-9",
74 "10.1016/0006-291x(75)90498-2",
75 "10.1016/0006-291x(75)90506-9",
76 "10.1016/0006-291x(75)90508-2",
77 "10.48550/arxiv.1509.08217",
78 "10.1016/0361-9230(93)90026-8",
79 "10.1184/r1/12841247.v1",
80 "10.1038/nature12373",
81 "10.3390/ijerph15061183",
82 "10.17605/osf.io/abcde",
83 "10.13039/100005522",
84 "10.11578/1367552",
85 "10.11221/jima.51.86",
86 "10.11185/imt.8.380",
87 "10.11230/jsts.17.2_1",
88 "10.11178/example.1",
89 "10.11178/example.2",
90 "10.1016/0022-0248(83)90411-6",
91 "10.1016/0038-1098(88)91128-3",
92 "10.11224/cleftpalate1976.23.2_83",
93 "10.11178/jdsa.8.49",
94 "10.11178/jdsa.5.47",
95 "10.11230/jsts.17.1_11",
96 "10.11450/seitaikogaku1989.10.1",
97 "10.11230/jsts.18.1_34",
98 "10.2494/photopolymer.12.209",
99 "10.1007/bf00354389",
100 "10.1007/bf00354390",
101 "10.1088/0954-0083/11/1/013",
102 "10.1177/0954008303015002003",
103 "10.1021/ma0201779",
104 "10.1246/cl.1997.333",
105 "10.1126/science.2563171",
106 "10.1016/0032-3861(95)90668-r",
107 "10.1016/0032-3861(95)90669-s",
108 "10.1088/0954-0083/11/1/008",
109 "10.1016/s0032-3861(02)00362-2",
110 "10.1093/comjnl/4.4.332",
111 "10.2307/1252042",
112 "10.1063/1.1656693",
113 "10.3233/978-1-61499-672-9-227",
114 "10.3233/ds-170012",
115 "10.1145/3360901.3364434",
116 "10.1007/978-3-030-61244-3_6",
117 "10.1007/978-3-030-62466-8_28",
118 "10.3897/bdj.3.e5063",
119 "10.1103/physrevd.84.084046",
120 "10.48550/arxiv.1107.5979",
121 "10.1001/10-v4n2-hsf10003",
122 "10.1001/jama.299.12.1471",
123 "10.1016/s0196-0644(99)70224-6",
124 "10.1056/nejmsa021807",
125 "10.1089/bsp.2008.0020",
126 "10.1097/01.bcr.0000155527.76205.a2",
127 "10.1097/01.ccm.0000151067.76074.21",
128 "10.1097/01.ccm.0000151072.17826.72",
129 "10.1097/dmp.0b013e31817196bf",
130 "10.1097/dmp.0b013e318194898d",
131 "10.1097/dmp.0b013e31819d977c",
132 "10.1097/dmp.0b013e31819f1ae2",
133 "10.1177/003335490812300219",
134 "10.1177/003335490912400218",
135 "10.1378/chest.07-2693",
136 "10.2105/ajph.2006.101626",
137 "10.2105/ajph.2009.162677",
138 "10.9799/ksfan.2012.25.1.069",
139 "10.9799/ksfan.2012.25.1.077",
140 "10.9799/ksfan.2012.25.1.083",
141 "10.9799/ksfan.2012.25.1.090",
142 "10.9799/ksfan.2012.25.1.099",
143 "10.9799/ksfan.2012.25.1.105",
144 "10.9799/ksfan.2012.25.1.116",
145 "10.9799/ksfan.2012.25.1.123",
146 "10.9799/ksfan.2012.25.1.132",
147 "10.9799/ksfan.2012.25.1.142",
148 "10.11426/nagare1970.2.3_3",
149 "10.11426/nagare1970.2.4_1",
150 "10.11426/nagare1970.3.3_13",
151 "10.14825/kaseki.68.0_14",
152 "10.14825/kaseki.68.0_18",
153 "10.1017/s0022112062000762",
154 "10.1295/kobunshi.16.842",
155 "10.1295/kobunshi.16.921",
156 "10.1002/zamm.19210010401",
157 "10.1002/zamm.19210010402",
158 "10.1126/science.235.4793.1156",
159 "10.1098/rstb.1989.0091",
160 "10.5575/geosoc.96.265",
161 "10.1007/s00266-017-1063-0",
162 "10.1016/s0006-3495(95)79925-8",
163 "10.1016/s0306-4530(03)00098-2",
164 "10.1021/bi00230a017",
165 "10.1080/2162402x.2015.1114203",
166 "10.1093/infdis/jir563",
167 "10.1137/1.9781611973730.123",
168 "10.1137/s0097539793255151",
169 "10.1172/jci115925",
170 "10.1186/s12891-018-2177-5",
171 "10.2466/pr0.1959.5.3.355",
172 "10.3171/jns.1980.53.6.0765",
173 "10.3389/fnana.2012.00034",
174 "10.3389/fnint.2013.00107",
175 "10.4021/wjon235w",
176 "10.48550/arxiv.1410.2266",
177 "10.5812/aapm.19333",
178 "10.1007/jhep03(2014)050",
179 "10.1016/0024-3795(84)90143-5",
180 "10.1093/ajcn/79.5.727",
181 "10.1109/sfcs.1981.28",
182 "10.1136/bjo.74.3.130-a",
183 "10.1186/1477-7827-12-11",
184 "10.1248/cpb.50.1128",
185 "10.1371/journal.pone.0060793",
186 "10.17511/jooo.2020.i06.02",
187 "10.18632/oncotarget.8868",
188 "10.2527/1995.7392834x",
189 "10.3390/ijms19082345",
190 "10.4103/abr.abr_141_17",
191 "10.48550/arxiv.1312.6380",
192 "10.48550/arxiv.1712.08660",
193 "10.7557/5.5607",
194 "10.48550/arxiv.1107.5979",
195 "10.5100/jje.33.1",
196 "10.11575/jet.v46i3.52198",
197 "10.11578/1367548",
198 "10.11578/1372474",
199 "10.11578/1480643",
200 "10.11578/dc.20191106.1",
201 "10.15407/scin11.06.057",
202 "10.1021/acs.jpclett.7b01097",
203 "10.1063/1.4973421",
204 "10.1371/journal.pone.0284601",
205 "10.1007/978-3-030-00668-6_8",
206 "10.1234/null-date",
207 "10.1234/empty-date",
208 "10.1234/no-dateparts",
209 "10.1234/html-title",
210 "10.1234/with-editor",
211 "10.1001/test.12345",
212 # DataCite test DOIs
213 "10.1016/j.archger.2019.103975",
214 "10.1016/j.archger.2020.104228",
215 "10.1016/j.clinbiomech.2022.105711",
216 "10.1016/j.humov.2013.06.005",
217 "10.1016/j.humov.2020.102588",
218 "10.1016/j.jbiomech.2014.07.010",
219 "10.1016/j.jbmt.2023.04.020",
220 "10.1021/acsami.3c04897",
221 "10.1080/00222895.2014.916651",
222 "10.1080/03091902.2022.2043947",
223 "10.1080/10749357.2022.2130620",
224 "10.1111/sms.12847",
225 "10.12678/1089-313x.21.4.151",
226 "10.1590/s0103-51502010000200003",
227 "10.2174/1871527315666151111120403",
228 # NOTE: 10.46979/rbn.v52i4.5546 is intentionally invalid for datacite tests
229 "10.5007/1980-0037.2014v16n3p287",
230 "10.5258/soton/d2733",
231 "10.5281/zenodo.8210025",
232 "10.5281/zenodo.8232826",
233 "10.5281/zenodo.8233112",
234 "10.5281/zenodo.8233113",
235 "10.5281/zenodo.8265216",
236 "10.5281/zenodo.8265217",
237 "10.6061/clinics/2013(11)07",
238 "10.5281/zenodo.8249952",
239 "10.5281/zenodo.8249970",
240 "10.1017/9781009157896",
241 "10.1017/9781009157896.005",
242 }
244 def doi_callback(request):
245 url_path = request.url.replace("https://doi.org/api/handles/", "")
246 doi = unquote(url_path).lower()
247 if doi in valid_dois:
248 return (200, {}, json_module.dumps({"responseCode": 1, "handle": doi}))
249 return (404, {}, json_module.dumps({"responseCode": 100}))
251 rsps.add_callback(
252 responses.GET,
253 re.compile(r"https://doi\.org/api/handles/.*"),
254 callback=doi_callback,
255 content_type="application/json",
256 )
259def _register_crossref_mocks(rsps: responses.RequestsMock) -> None:
260 valid_members = {
261 "297": {"id": 297, "primary-name": "IWA Publishing"},
262 "4443": {"id": 4443, "primary-name": "Example Publisher"},
263 "78": {"id": 78, "primary-name": "Elsevier BV"},
264 "311": {"id": 311, "primary-name": "MDPI"},
265 }
267 def crossref_members_callback(request):
268 member_id = request.url.split("/")[-1]
269 if member_id in valid_members:
270 return (
271 200,
272 {},
273 json_module.dumps({"status": "ok", "message": valid_members[member_id]}),
274 )
275 return (404, {}, "")
277 rsps.add_callback(
278 responses.GET,
279 re.compile(r"https://api\.crossref\.org/members/.*"),
280 callback=crossref_members_callback,
281 content_type="application/json",
282 )
284 crossref_works_responses = {
285 "10.1038/nature12373": {
286 "DOI": "10.1038/nature12373",
287 "type": "journal-article",
288 "title": ["Nanometre-scale thermometry in a living cell"],
289 "author": [
290 {"given": "G.", "family": "Kucsko", "sequence": "first"},
291 {"given": "P. C.", "family": "Maurer", "sequence": "additional"},
292 {"given": "M. D.", "family": "Lukin", "sequence": "additional"}
293 ],
294 "container-title": ["Nature"],
295 "volume": "500",
296 "issue": "7460",
297 "page": "54-58",
298 "issued": {"date-parts": [[2013, 7, 31]]},
299 "ISSN": ["0028-0836", "1476-4687"],
300 "publisher": "Springer Science and Business Media LLC",
301 "member": "297",
302 "prefix": "10.1038"
303 },
304 "10.1371/journal.pone.0284601": {
305 "DOI": "10.1371/journal.pone.0284601",
306 "type": "journal-article",
307 "title": ["Biochemical evaluation of vaccination in rats"],
308 "author": [
309 {"given": "Mahsa", "family": "Teymoorzadeh", "sequence": "first"},
310 {"given": "Razieh", "family": "Yazdanparast", "sequence": "additional",
311 "ORCID": "https://orcid.org/0000-0003-0530-4305", "authenticated-orcid": True}
312 ],
313 "container-title": ["PLOS ONE"],
314 "volume": "18",
315 "issue": "5",
316 "page": "e0284601",
317 "issued": {"date-parts": [[2023, 5, 4]]},
318 "ISSN": ["1932-6203"],
319 "publisher": "Public Library of Science (PLoS)"
320 },
321 "10.1007/978-3-030-00668-6_8": {
322 "DOI": "10.1007/978-3-030-00668-6_8",
323 "type": "book-chapter",
324 "title": ["The SPAR Ontologies"],
325 "author": [
326 {"given": "Silvio", "family": "Peroni", "sequence": "first"},
327 {"given": "David", "family": "Shotton", "sequence": "additional"}
328 ],
329 "container-title": ["Lecture Notes in Computer Science", "The Semantic Web – ISWC 2018"],
330 "page": "119-136",
331 "issued": {"date-parts": [[2018]]},
332 "ISBN": ["9783030006679", "9783030006686"],
333 "publisher": "Springer International Publishing"
334 },
335 "10.1234/null-date": {
336 "DOI": "10.1234/null-date",
337 "type": "journal-article",
338 "title": ["Article with null date"],
339 "issued": {"date-parts": [[None]]}
340 },
341 "10.1234/empty-date": {
342 "DOI": "10.1234/empty-date",
343 "type": "journal-article",
344 "title": ["Article with empty date-parts"],
345 "issued": {"date-parts": [[]]}
346 },
347 "10.1234/no-dateparts": {
348 "DOI": "10.1234/no-dateparts",
349 "type": "journal-article",
350 "title": ["Article without date-parts key"],
351 "issued": {}
352 },
353 "10.1234/html-title": {
354 "DOI": "10.1234/html-title",
355 "type": "journal-article",
356 "title": ["A study of <i>Escherichia coli</i> in <b>biofilms</b>"],
357 "issued": {"date-parts": [[2024, 1, 15]]}
358 },
359 "10.1234/with-editor": {
360 "DOI": "10.1234/with-editor",
361 "type": "edited-book",
362 "title": ["Edited volume test"],
363 "author": [{"given": "John", "family": "Doe", "sequence": "first"}],
364 "editor": [{"given": "Jane", "family": "Smith", "sequence": "first"}],
365 "issued": {"date-parts": [[2024, 6, 20]]}
366 },
367 }
369 def crossref_works_callback(request):
370 doi = unquote(request.url.split("/works/")[-1]).lower()
371 if doi in crossref_works_responses:
372 return (200, {}, json_module.dumps({"status": "ok", "message": crossref_works_responses[doi]}))
373 return (200, {}, json_module.dumps({"status": "ok", "message": {"DOI": doi}}))
375 rsps.add_callback(
376 responses.GET,
377 re.compile(r"https://api\.crossref\.org/works/.*"),
378 callback=crossref_works_callback,
379 content_type="application/json",
380 )
382 prefix_to_publisher = {
383 "10.1016": ("Elsevier BV", "78"),
384 "10.1136": ("BMJ", "239"),
385 "10.1021": ("American Chemical Society (ACS)", "316"),
386 "10.1007": ("Springer Science and Business Media LLC", "297"),
387 "10.1097": ("Ovid Technologies (Wolters Kluwer Health)", "276"),
388 "10.1378": ("Elsevier BV", "78"),
389 "10.1055": ("Georg Thieme Verlag KG", "194"),
390 "10.1080": ("Informa UK Limited", "301"),
391 "10.1210": ("The Endocrine Society", "13"),
392 "10.1159": ("S. Karger AG", "32"),
393 "10.3233": ("IOS Press", "2428"),
394 }
396 def crossref_prefixes_callback(request):
397 prefix = request.url.split("/")[-1]
398 if prefix in prefix_to_publisher:
399 name, member_id = prefix_to_publisher[prefix]
400 return (
401 200,
402 {},
403 json_module.dumps({
404 "status": "ok",
405 "message": {
406 "prefix": prefix,
407 "name": name,
408 "member": f"http://id.crossref.org/member/{member_id}"
409 }
410 }),
411 )
412 return (404, {}, "")
414 rsps.add_callback(
415 responses.GET,
416 re.compile(r"https://api\.crossref\.org/prefixes/.*"),
417 callback=crossref_prefixes_callback,
418 content_type="application/json",
419 )
422def _register_arxiv_mocks(rsps: responses.RequestsMock) -> None:
423 valid_arxiv_xml = """<?xml version="1.0" encoding="UTF-8"?>
424<feed xmlns="http://www.w3.org/2005/Atom" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/">
425 <opensearch:totalResults>1</opensearch:totalResults>
426 <entry>
427 <id>http://arxiv.org/abs/{arxiv_id}</id>
428 <title>Example Paper Title</title>
429 </entry>
430</feed>"""
432 invalid_arxiv_xml = """<?xml version="1.0" encoding="UTF-8"?>
433<feed xmlns="http://www.w3.org/2005/Atom" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/">
434 <opensearch:totalResults>0</opensearch:totalResults>
435</feed>"""
437 valid_ids = {"2109.05583", "2109.05582", "1509.08217", "1107.5979", "1410.2266", "1712.08660", "1312.6380"}
438 valid_versions = {"2109.05583v2", "1509.08217v1", "1107.5979v1", "1410.2266v1", "1712.08660v1", "1312.6380v1"}
440 def arxiv_api_callback(request):
441 url = request.url
442 if "search_query=all:" in url:
443 arxiv_id = url.split("search_query=all:")[-1]
444 arxiv_id = unquote(arxiv_id)
445 if arxiv_id in valid_ids:
446 return (200, {}, valid_arxiv_xml.format(arxiv_id=arxiv_id))
447 return (200, {}, invalid_arxiv_xml)
448 return (404, {}, "")
450 rsps.add_callback(
451 responses.GET,
452 re.compile(r"https://export\.arxiv\.org/api/query.*"),
453 callback=arxiv_api_callback,
454 content_type="application/xml",
455 )
457 def arxiv_abs_callback(request):
458 url = request.url
459 arxiv_id = url.split("/abs/")[-1]
460 if arxiv_id in valid_versions:
461 return (200, {}, "<html><body>ArXiv paper</body></html>")
462 return (404, {}, "")
464 rsps.add_callback(
465 responses.GET,
466 re.compile(r"https://arxiv\.org/abs/.*"),
467 callback=arxiv_abs_callback,
468 content_type="text/html",
469 )
472def _register_pmid_mocks(rsps: responses.RequestsMock) -> None:
473 valid_pmid_html = """<html><body>
474<div id="article-details">
475PMID- {pmid}
476TI - Brevetoxin depresses synaptic transmission in guinea pig hippocampal slices.
477FAU - Adler, M
478FAU - Sheridan, R E
479FAU - Apland, J P
480DP - 1993
481TA - Brain research bulletin
482VI - 31
483IP - 1-2
484PG - 201-7
485IS - 0361-9230
486AID - 10.1016/0361-9230(93)90026-8 [doi]
487</div></body></html>"""
489 valid_pmids = {
490 "2942070", "1509982", "8384044", "6716460",
491 "20662931", "12345", "5", "1", "2", "3", "4",
492 "24484640", "21887584", "29890726", "23483834", "2938",
493 "1056020", "4882249", "14834145", "5509841", "5059118",
494 "118", "120", "351", "352", "353", "324",
495 "1387883", "19934524", "20879334", "21949042", "22952459",
496 "23199016", "25340169", "27429628", "27467927", "29147199",
497 "30064399", "8527666", "8946776", "11169242", "15113710",
498 "1581770", "16277675", "2322507", "23577161", "24632350",
499 "29416127", "29456979", "30096915", "7441336", "28383409",
500 "8582874", "9488524", "12192153", "12892987", "21533295",
501 "24363676", "24409128", "24479789", "25893183", "27105522", "29305643",
502 }
504 def pmid_callback(request):
505 url = request.url
506 match = re.search(r"/(\d+)/", url)
507 if match:
508 pmid = match.group(1)
509 if pmid in valid_pmids:
510 return (200, {}, valid_pmid_html.format(pmid=pmid))
511 return (404, {}, "")
513 rsps.add_callback(
514 responses.GET,
515 re.compile(r"https://pubmed\.ncbi\.nlm\.nih\.gov/.*"),
516 callback=pmid_callback,
517 content_type="text/html",
518 )
521def _register_orcid_mocks(rsps: responses.RequestsMock) -> None:
522 specific_orcids = {
523 "0000-0001-5506-523X": {
524 "orcid-identifier": {"path": "0000-0001-5506-523X"},
525 "person": {
526 "name": {"family-name": {"value": "Shotton"}, "given-names": {"value": "David"}},
527 "emails": {"email": []},
528 "external-identifiers": {"external-identifier": []},
529 },
530 "history": {
531 "submission-date": {"value": 1351641600000},
532 "last-modified-date": {"value": 1700000000000},
533 },
534 },
535 }
536 generic_valid_orcids = {
537 "0000-0003-0530-4305",
538 "0000-0001-8513-8700", "0000-0002-9286-2630",
539 "0000-0001-9597-7030", "0000-0002-8210-7076",
540 "0000-0001-9759-3938", "0000-0003-4082-1500",
541 "0000-0002-6227-4053", "0000-0002-0861-0511",
542 "0000-0002-2149-4113", "0000-0001-6946-5074",
543 "0000-0001-5096-5538", "0000-0001-5115-3099",
544 "0000-0001-6174-9013", "0000-0001-6293-0113",
545 "0000-0001-6419-1668", "0000-0001-9831-6254",
546 "0000-0002-1844-174x", "0000-0002-5266-9991",
547 "0000-0002-6396-4603", "0000-0003-0585-8228",
548 "0000-0003-2921-5606", "0000-0003-4409-2261",
549 "0000-0001-8128-1032", "0000-0002-0743-7905",
550 "0000-0002-4847-4163", "0000-0002-8454-1159",
551 "0000-0003-1094-3363", "0000-0003-1223-5934",
552 "0000-0003-2712-1825",
553 "0000-0001-6147-9981", "0000-0001-7392-1415",
554 "0000-0001-7543-3466", "0000-0001-9940-8409",
555 "0000-0002-0801-0890", "0000-0002-3019-5377",
556 "0000-0002-5870-1542", "0000-0002-6210-8370",
557 "0000-0002-6715-3533", "0000-0002-8013-9947",
558 "0000-0002-9747-4928", "0000-0003-0621-9209",
559 "0000-0003-1445-0291", "0000-0003-2185-3267",
560 "0000-0003-2328-5769", "0000-0003-2713-8387",
561 "0000-0003-4149-9760",
562 }
563 base_orcid_data = {
564 "person": {
565 "name": {"family-name": {"value": "Test"}, "given-names": {"value": "User"}},
566 "emails": {"email": []},
567 "external-identifiers": {"external-identifier": []},
568 },
569 "history": {
570 "submission-date": {"value": 1351641600000},
571 "last-modified-date": {"value": 1700000000000},
572 },
573 }
575 def orcid_callback(request):
576 orcid = request.url.split("/")[-1]
577 if orcid in specific_orcids:
578 return (200, {}, json_module.dumps(specific_orcids[orcid]))
579 if orcid in generic_valid_orcids:
580 data = dict(base_orcid_data)
581 data["orcid-identifier"] = {"path": orcid}
582 return (200, {}, json_module.dumps(data))
583 return (404, {}, "")
585 rsps.add_callback(
586 responses.GET,
587 re.compile(r"https://pub\.orcid\.org/v3\.0/.*"),
588 callback=orcid_callback,
589 content_type="application/json",
590 )
593def _register_openalex_mocks(rsps: responses.RequestsMock) -> None:
594 valid_works = {
595 "W2013228336": {"id": "https://openalex.org/W2013228336", "title": "Example"},
596 "W748315831": {"id": "https://openalex.org/W748315831", "title": "Example 2"},
597 }
598 valid_sources = {
599 "S4210229581": {
600 "id": "https://openalex.org/S4210229581",
601 "display_name": "Example Source",
602 },
603 }
605 def openalex_callback(request):
606 url = request.url
607 for work_id, data in valid_works.items():
608 if work_id in url:
609 return (200, {}, json_module.dumps(data))
610 for source_id, data in valid_sources.items():
611 if source_id in url:
612 return (200, {}, json_module.dumps(data))
613 return (404, {}, "")
615 rsps.add_callback(
616 responses.GET,
617 re.compile(r"https://api\.openalex\.org/.*"),
618 callback=openalex_callback,
619 content_type="application/json",
620 )
623def _register_pmc_mocks(rsps: responses.RequestsMock) -> None:
624 valid_pmcs = {
625 "PMC8384044": {
626 "records": [
627 {"pmcid": "PMC8384044", "pmid": "34356789", "doi": "10.1234/example1"}
628 ]
629 },
630 "PMC6716460": {
631 "records": [
632 {"pmcid": "PMC6716460", "pmid": "31456789", "doi": "10.1234/example2"}
633 ]
634 },
635 "PMC3928621": {
636 "records": [
637 {"pmcid": "PMC3928621", "pmid": "24484640", "doi": "10.2307/3053861"}
638 ]
639 },
640 "PMC5555555": {
641 "records": [
642 {"pmcid": "PMC5555555", "pmid": "12345678", "doi": "10.1234/example3"}
643 ]
644 },
645 "PMC2873764": {
646 "records": [
647 {"pmcid": "PMC2873764", "pmid": "20662931", "doi": "10.1186/1471-2164-11-245"}
648 ]
649 },
650 "PMC1236277": {"records": [{"pmcid": "PMC1236277", "pmid": "16277675"}]},
651 "PMC329969": {"records": [{"pmcid": "PMC329969", "pmid": "1387883"}]},
652 "PMC3429885": {"records": [{"pmcid": "PMC3429885", "pmid": "22952459"}]},
653 "PMC4206050": {"records": [{"pmcid": "PMC4206050", "pmid": "25340169"}]},
654 "PMC4634289": {"records": [{"pmcid": "PMC4634289", "pmid": "29147199"}]},
655 "PMC4910730": {"records": [{"pmcid": "PMC4910730", "pmid": "27467927"}]},
656 "PMC4933747": {"records": [{"pmcid": "PMC4933747", "pmid": "27429628"}]},
657 "PMC5649856": {"records": [{"pmcid": "PMC5649856", "pmid": "29147199"}]},
658 "PMC6069818": {"records": [{"pmcid": "PMC6069818", "pmid": "30064399"}]},
659 "PMC1042030": {"records": [{"pmcid": "PMC1042030", "pmid": "1581770"}]},
660 "PMC1042034": {"records": [{"pmcid": "PMC1042034", "pmid": "2322507"}]},
661 "PMC1297570": {"records": [{"pmcid": "PMC1297570", "pmid": "16277675"}]},
662 "PMC3618337": {"records": [{"pmcid": "PMC3618337", "pmid": "23577161"}]},
663 "PMC4005913": {"records": [{"pmcid": "PMC4005913", "pmid": "24632350"}]},
664 "PMC5777326": {"records": [{"pmcid": "PMC5777326", "pmid": "29416127"}]},
665 "PMC5812102": {"records": [{"pmcid": "PMC5812102", "pmid": "29456979"}]},
666 "PMC6025535": {"records": [{"pmcid": "PMC6025535", "pmid": "29890726"}]},
667 "PMC6121471": {"records": [{"pmcid": "PMC6121471", "pmid": "30096915"}]},
668 "PMC5411193": {"records": [{"pmcid": "PMC5411193", "pmid": "28383409"}]},
669 "PMC1191243": {"records": [{"pmcid": "PMC1191243", "pmid": "16277675"}]},
670 "PMC3869588": {"records": [{"pmcid": "PMC3869588", "pmid": "24363676"}]},
671 "PMC3885986": {"records": [{"pmcid": "PMC3885986", "pmid": "24409128"}]},
672 "PMC3922134": {"records": [{"pmcid": "PMC3922134", "pmid": "24479789"}]},
673 "PMC4377162": {"records": [{"pmcid": "PMC4377162", "pmid": "25893183"}]},
674 "PMC5058700": {"records": [{"pmcid": "PMC5058700", "pmid": "27105522"}]},
675 "PMC5840246": {"records": [{"pmcid": "PMC5840246", "pmid": "29305643"}]},
676 }
678 def pmc_callback(request):
679 url = request.url
680 for pmc_id, data in valid_pmcs.items():
681 if pmc_id in url:
682 return (200, {}, json_module.dumps(data))
683 return (200, {}, json_module.dumps({"records": [{"status": "error", "errmsg": "not found"}]}))
685 rsps.add_callback(
686 responses.GET,
687 re.compile(r".*ncbi\.nlm\.nih\.gov/pmc/utils/idconv/.*"),
688 callback=pmc_callback,
689 content_type="application/json",
690 )
693def _register_datacite_mocks(rsps: responses.RequestsMock) -> None:
694 def datacite_callback(request):
695 return (404, {}, "")
697 rsps.add_callback(
698 responses.GET,
699 re.compile(r"https://api\.datacite\.org/dois/.*"),
700 callback=datacite_callback,
701 content_type="application/json",
702 )
705def _register_jid_mocks(rsps: responses.RequestsMock) -> None:
706 valid_jids = {"otoljpn1970", "jscej1944b", "japeoj"}
708 valid_xml = """<?xml version="1.0" encoding="UTF-8"?>
709<result xmlns="http://www.w3.org/2005/Atom">
710 <status>0</status>
711 <entry><title>Example Journal</title></entry>
712</result>"""
714 invalid_xml = """<?xml version="1.0" encoding="UTF-8"?>
715<result xmlns="http://www.w3.org/2005/Atom">
716 <status>ERR_001</status>
717</result>"""
719 def jid_api_callback(request):
720 url = request.url
721 for jid in valid_jids:
722 if f"cdjournal={jid}" in url:
723 return (200, {}, valid_xml)
724 return (200, {}, invalid_xml)
726 rsps.add_callback(
727 responses.GET,
728 re.compile(r"https://api\.jstage\.jst\.go\.jp/searchapi/.*"),
729 callback=jid_api_callback,
730 content_type="application/xml",
731 )
733 def jid_browse_callback(request):
734 url = request.url
735 for jid in valid_jids:
736 if jid in url:
737 return (200, {}, '<html><div id="page-content">Journal Page</div></html>')
738 return (404, {}, "")
740 rsps.add_callback(
741 responses.GET,
742 re.compile(r"https://www\.jstage\.jst\.go\.jp/browse/.*"),
743 callback=jid_browse_callback,
744 content_type="text/html",
745 )
748def _register_ror_mocks(rsps: responses.RequestsMock) -> None:
749 valid_rors = {
750 "040jc3p57", "01111rn36", "0138va192", "00wb4mk85",
751 "03ztgj037", "03ztgj039", "041qv0h25", "04wxnsj81", "04wxnsj89",
752 }
754 def ror_callback(request):
755 url = request.url
756 for ror_id in valid_rors:
757 if ror_id in url:
758 return (200, {}, json_module.dumps({"id": f"https://ror.org/{ror_id}", "name": "Example Org"}))
759 return (404, {}, "")
761 rsps.add_callback(
762 responses.GET,
763 re.compile(r"https://api\.ror\.org/organizations/.*"),
764 callback=ror_callback,
765 content_type="application/json",
766 )
769def _register_viaf_mocks(rsps: responses.RequestsMock) -> None:
770 valid_viafs = {
771 "5604148947771454950004", "234145033", "56752857",
772 "148463773", "102333412",
773 }
775 def viaf_callback(request):
776 url = request.url
777 for viaf_id in valid_viafs:
778 if viaf_id in url:
779 return (200, {}, json_module.dumps({
780 "ns1:VIAFCluster": {"ns1:viafID": viaf_id}
781 }))
782 return (404, {}, "")
784 rsps.add_callback(
785 responses.GET,
786 re.compile(r"https?://viaf\.org/viaf/.*"),
787 callback=viaf_callback,
788 content_type="application/json",
789 )
792def _register_wikidata_mocks(rsps: responses.RequestsMock) -> None:
793 valid_wikidata_ids = {"Q34433", "Q24698708", "Q15767074", "Q7842", "Q42"}
795 def wikidata_callback(request):
796 url = request.url
797 for wikidata_id in valid_wikidata_ids:
798 if wikidata_id in url:
799 return (200, {}, json_module.dumps({
800 "entities": {wikidata_id: {"id": wikidata_id, "type": "item"}}
801 }))
802 return (404, {}, "")
804 rsps.add_callback(
805 responses.GET,
806 re.compile(r"https://www\.wikidata\.org/wiki/Special:EntityData/.*"),
807 callback=wikidata_callback,
808 content_type="application/json",
809 )
812def _register_wikipedia_mocks(rsps: responses.RequestsMock) -> None:
813 valid_wikipedia_ids = {"30456", "43744177"}
815 def wikipedia_callback(request):
816 url = request.url
817 for wiki_id in valid_wikipedia_ids:
818 if f"pageids={wiki_id}" in url or f"pageids%3D{wiki_id}" in url:
819 return (200, {}, json_module.dumps({
820 "query": {"pages": {wiki_id: {"pageid": int(wiki_id), "title": "Example Page"}}}
821 }))
822 return (200, {}, json_module.dumps({"query": {"pages": {}}}))
824 rsps.add_callback(
825 responses.GET,
826 re.compile(r"https://en\.wikipedia\.org/w/api\.php.*"),
827 callback=wikipedia_callback,
828 content_type="application/json",
829 )
832def _register_medra_mocks(rsps: responses.RequestsMock) -> None:
833 medra_article_xml = """<?xml version="1.0" encoding="UTF-8"?>
834<ONIXDOISerialArticleWorkRegistrationMessage xmlns="http://www.editeur.org/onix/DOIMetadata/2.0">
835 <Header>
836 <FromCompany>mEDRA</FromCompany>
837 <FromEmail>medra@medra.org</FromEmail>
838 <ToCompany>PublicService</ToCompany>
839 <SentDate>20260305</SentDate>
840 </Header>
841 <DOISerialArticleWork>
842 <NotificationType>07</NotificationType>
843 <DOI>10.3233/DS-210053</DOI>
844 <DOIWebsiteLink>https://www.medra.org/servlet/aliasResolver?alias=iospress&doi=10.3233/DS-210053</DOIWebsiteLink>
845 <RegistrantName>Default Registrant</RegistrantName>
846 <RegistrationAuthority>mEDRA</RegistrationAuthority>
847 <SerialPublication>
848 <SerialWork>
849 <WorkIdentifier>
850 <WorkIDType>16</WorkIDType>
851 <IDValue>2451-8484</IDValue>
852 </WorkIdentifier>
853 <Title>
854 <TitleType>01</TitleType>
855 <TitleText>Data Science</TitleText>
856 </Title>
857 <Publisher>
858 <PublishingRole>01</PublishingRole>
859 <PublisherName>IOS Press</PublisherName>
860 </Publisher>
861 <CountryOfPublication>NL</CountryOfPublication>
862 </SerialWork>
863 <SerialVersion>
864 <ProductIdentifier>
865 <ProductIDType>07</ProductIDType>
866 <IDValue>24518492</IDValue>
867 </ProductIdentifier>
868 <ProductForm>JD</ProductForm>
869 </SerialVersion>
870 <SerialVersion>
871 <ProductIdentifier>
872 <ProductIDType>07</ProductIDType>
873 <IDValue>24518484</IDValue>
874 </ProductIdentifier>
875 <ProductForm>JB</ProductForm>
876 </SerialVersion>
877 </SerialPublication>
878 <JournalIssue>
879 <JournalVolumeNumber>5</JournalVolumeNumber>
880 <JournalIssueNumber>2</JournalIssueNumber>
881 <JournalIssueDate>
882 <DateFormat>00</DateFormat>
883 <Date>20220720</Date>
884 </JournalIssueDate>
885 </JournalIssue>
886 <ContentItem>
887 <TextItem>
888 <TextItemType>10</TextItemType>
889 <PageRun>
890 <FirstPageNumber>97</FirstPageNumber>
891 <LastPageNumber>138</LastPageNumber>
892 </PageRun>
893 </TextItem>
894 <Title>
895 <TitleType>01</TitleType>
896 <TitleText>Packaging research artefacts with RO-Crate</TitleText>
897 </Title>
898 <Contributor>
899 <SequenceNumber>1</SequenceNumber>
900 <ContributorRole>A01</ContributorRole>
901 <NameIdentifier><NameIDType>21</NameIDType><IDValue>https://orcid.org/0000-0001-9842-9718</IDValue></NameIdentifier>
902 <PersonNameInverted>Soiland-Reyes, Stian</PersonNameInverted>
903 </Contributor>
904 <Contributor>
905 <SequenceNumber>2</SequenceNumber>
906 <ContributorRole>A01</ContributorRole>
907 <NameIdentifier><NameIDType>21</NameIDType><IDValue>https://orcid.org/0000-0002-3545-944X</IDValue></NameIdentifier>
908 <PersonNameInverted>Sefton, Peter</PersonNameInverted>
909 </Contributor>
910 <Contributor>
911 <SequenceNumber>3</SequenceNumber>
912 <ContributorRole>A01</ContributorRole>
913 <NameIdentifier><NameIDType>21</NameIDType><IDValue>https://orcid.org/0000-0003-1304-1939</IDValue></NameIdentifier>
914 <PersonNameInverted>Crosas, Mercè</PersonNameInverted>
915 </Contributor>
916 <Contributor>
917 <SequenceNumber>4</SequenceNumber>
918 <ContributorRole>A01</ContributorRole>
919 <NameIdentifier><NameIDType>21</NameIDType><IDValue>https://orcid.org/0000-0003-3986-0510</IDValue></NameIdentifier>
920 <PersonNameInverted>Castro, Leyla Jael</PersonNameInverted>
921 </Contributor>
922 <Contributor>
923 <SequenceNumber>5</SequenceNumber>
924 <ContributorRole>A01</ContributorRole>
925 <NameIdentifier><NameIDType>21</NameIDType><IDValue>https://orcid.org/0000-0001-6565-5145</IDValue></NameIdentifier>
926 <PersonNameInverted>Coppens, Frederik</PersonNameInverted>
927 </Contributor>
928 <Contributor>
929 <SequenceNumber>6</SequenceNumber>
930 <ContributorRole>A01</ContributorRole>
931 <NameIdentifier><NameIDType>21</NameIDType><IDValue>https://orcid.org/0000-0002-4806-5140</IDValue></NameIdentifier>
932 <PersonNameInverted>Fernández, José M.</PersonNameInverted>
933 </Contributor>
934 <Contributor>
935 <SequenceNumber>7</SequenceNumber>
936 <ContributorRole>A01</ContributorRole>
937 <NameIdentifier><NameIDType>21</NameIDType><IDValue>https://orcid.org/0000-0003-0454-7145</IDValue></NameIdentifier>
938 <PersonNameInverted>Garijo, Daniel</PersonNameInverted>
939 </Contributor>
940 <Contributor>
941 <SequenceNumber>8</SequenceNumber>
942 <ContributorRole>A01</ContributorRole>
943 <NameIdentifier><NameIDType>21</NameIDType><IDValue>https://orcid.org/0000-0002-3079-6586</IDValue></NameIdentifier>
944 <PersonNameInverted>Grüning, Björn</PersonNameInverted>
945 </Contributor>
946 <Contributor>
947 <SequenceNumber>9</SequenceNumber>
948 <ContributorRole>A01</ContributorRole>
949 <NameIdentifier><NameIDType>21</NameIDType><IDValue>https://orcid.org/0000-0001-5383-6993</IDValue></NameIdentifier>
950 <PersonNameInverted>La Rosa, Marco</PersonNameInverted>
951 </Contributor>
952 <Contributor>
953 <SequenceNumber>10</SequenceNumber>
954 <ContributorRole>A01</ContributorRole>
955 <NameIdentifier><NameIDType>21</NameIDType><IDValue>https://orcid.org/0000-0001-8271-5429</IDValue></NameIdentifier>
956 <PersonNameInverted>Leo, Simone</PersonNameInverted>
957 </Contributor>
958 <Contributor>
959 <SequenceNumber>11</SequenceNumber>
960 <ContributorRole>A01</ContributorRole>
961 <NameIdentifier><NameIDType>21</NameIDType><IDValue>https://orcid.org/0000-0001-8131-2150</IDValue></NameIdentifier>
962 <PersonNameInverted>Ó Carragáin, Eoghan</PersonNameInverted>
963 </Contributor>
964 <Contributor>
965 <SequenceNumber>12</SequenceNumber>
966 <ContributorRole>A01</ContributorRole>
967 <NameIdentifier><NameIDType>21</NameIDType><IDValue>https://orcid.org/0000-0002-9648-6484</IDValue></NameIdentifier>
968 <PersonNameInverted>Portier, Marc</PersonNameInverted>
969 </Contributor>
970 <Contributor>
971 <SequenceNumber>13</SequenceNumber>
972 <ContributorRole>A01</ContributorRole>
973 <NameIdentifier><NameIDType>21</NameIDType><IDValue>https://orcid.org/0000-0003-1991-0533</IDValue></NameIdentifier>
974 <PersonNameInverted>Trisovic, Ana</PersonNameInverted>
975 </Contributor>
976 <Contributor>
977 <SequenceNumber>14</SequenceNumber>
978 <ContributorRole>A01</ContributorRole>
979 <PersonNameInverted>RO-Crate Community</PersonNameInverted>
980 </Contributor>
981 <Contributor>
982 <SequenceNumber>15</SequenceNumber>
983 <ContributorRole>A01</ContributorRole>
984 <NameIdentifier><NameIDType>21</NameIDType><IDValue>https://orcid.org/0000-0003-0183-6910</IDValue></NameIdentifier>
985 <PersonNameInverted>Groth, Paul</PersonNameInverted>
986 </Contributor>
987 <Contributor>
988 <SequenceNumber>16</SequenceNumber>
989 <ContributorRole>A01</ContributorRole>
990 <NameIdentifier><NameIDType>21</NameIDType><IDValue>https://orcid.org/0000-0003-1219-2137</IDValue></NameIdentifier>
991 <PersonNameInverted>Goble, Carole</PersonNameInverted>
992 </Contributor>
993 <Contributor>
994 <SequenceNumber>17</SequenceNumber>
995 <ContributorRole>B01</ContributorRole>
996 <NameIdentifier><NameIDType>21</NameIDType><IDValue>https://orcid.org/0000-0003-0530-4305</IDValue></NameIdentifier>
997 <PersonNameInverted>Peroni, Silvio</PersonNameInverted>
998 </Contributor>
999 <PublicationDate>20220720</PublicationDate>
1000 </ContentItem>
1001 </DOISerialArticleWork>
1002</ONIXDOISerialArticleWorkRegistrationMessage>"""
1004 medra_book_xml = """<?xml version="1.0" encoding="UTF-8"?>
1005<ONIXDOIMonographicProductRegistrationMessage xmlns="http://www.editeur.org/onix/DOIMetadata/2.0">
1006 <Header>
1007 <FromCompany>mEDRA</FromCompany>
1008 <FromEmail>medra@medra.org</FromEmail>
1009 <ToCompany>PublicService</ToCompany>
1010 <SentDate>20260305</SentDate>
1011 </Header>
1012 <DOIMonographicProduct>
1013 <NotificationType>06</NotificationType>
1014 <DOI>10.23775/20221026</DOI>
1015 <DOIWebsiteLink>https://perosh.eu/wp-content/uploads/2022/10/Book-of-Abstracts_2nd-PEROSH-PWL-conference_DOI-10.23775-20221026.pdf</DOIWebsiteLink>
1016 <RegistrantName>PEROSH</RegistrantName>
1017 <RegistrationAuthority>mEDRA</RegistrationAuthority>
1018 <ProductForm>DA</ProductForm>
1019 <Title>
1020 <TitleType>01</TitleType>
1021 <TitleText>Book of Abstract: 2nd International PEROSH conference on Prolonging Working Life</TitleText>
1022 </Title>
1023 <Contributor>
1024 <SequenceNumber>1</SequenceNumber>
1025 <ContributorRole>A01</ContributorRole>
1026 <CorporateName>PEROSH member institutes</CorporateName>
1027 </Contributor>
1028 <Language>
1029 <LanguageRole>01</LanguageRole>
1030 <LanguageCode>eng</LanguageCode>
1031 </Language>
1032 <Publisher>
1033 <PublishingRole>01</PublishingRole>
1034 <PublisherName>PEROSH</PublisherName>
1035 </Publisher>
1036 <CountryOfPublication>SE</CountryOfPublication>
1037 <PublicationDate>202209</PublicationDate>
1038 </DOIMonographicProduct>
1039</ONIXDOIMonographicProductRegistrationMessage>"""
1041 medra_series_xml = """<?xml version="1.0" encoding="UTF-8"?>
1042<ONIXDOISerialTitleWorkRegistrationMessage xmlns="http://www.editeur.org/onix/DOIMetadata/2.0">
1043 <Header>
1044 <FromCompany>mEDRA</FromCompany>
1045 <FromEmail>medra@medra.org</FromEmail>
1046 <ToCompany>PublicService</ToCompany>
1047 <SentDate>20260305</SentDate>
1048 </Header>
1049 <DOISerialTitleWork>
1050 <NotificationType>07</NotificationType>
1051 <DOI>10.17426/58141</DOI>
1052 <DOIWebsiteLink>https://www.centroricercheroma.it/prodotto/laquila-oltre-i-terremoti-costruzioni-e-ricostruzioni-della-citta/</DOIWebsiteLink>
1053 <RegistrantName>CROMA - UNIVERSITÀ ROMA TRE</RegistrantName>
1054 <RegistrationAuthority>mEDRA</RegistrationAuthority>
1055 <SerialPublication>
1056 <SerialWork>
1057 <Title language="ita">
1058 <TitleType>01</TitleType>
1059 <TitleText>L’Aquila oltre i terremoti. Costruzioni e ricostruzioni della città a cura di Simonetta Ciranna e Manuel Vaquero Piñeiro</TitleText>
1060 </Title>
1061 <Publisher>
1062 <PublishingRole>01</PublishingRole>
1063 <PublisherIdentifier>
1064 <PublisherIDType>01</PublisherIDType>
1065 <IDValue>1</IDValue>
1066 </PublisherIdentifier>
1067 <PublisherName>CROMA - UNIVERSITÀ ROMA TRE</PublisherName>
1068 </Publisher>
1069 <CountryOfPublication>IT</CountryOfPublication>
1070 </SerialWork>
1071 </SerialPublication>
1072 <Language>
1073 <LanguageRole>01</LanguageRole>
1074 <LanguageCode>ita</LanguageCode>
1075 </Language>
1076 <PublishingStatus>04</PublishingStatus>
1077 <DateFirstPublished>
1078 <DateFormat>00</DateFormat>
1079 <Date>20110708</Date>
1080 </DateFirstPublished>
1081 </DOISerialTitleWork>
1082</ONIXDOISerialTitleWorkRegistrationMessage>"""
1084 medra_chapter_xml = """<?xml version="1.0" encoding="UTF-8"?>
1085<ONIXDOIMonographChapterWorkRegistrationMessage xmlns="http://www.editeur.org/onix/DOIMetadata/2.0">
1086 <Header>
1087 <FromCompany>mEDRA</FromCompany>
1088 <FromEmail>medra@medra.org</FromEmail>
1089 <ToCompany>PublicService</ToCompany>
1090 <SentDate>20260305</SentDate>
1091 </Header>
1092 <DOIMonographChapterWork>
1093 <NotificationType>06</NotificationType>
1094 <DOI>10.2357/9783739880303-105</DOI>
1095 <DOIWebsiteLink>https://elibrary.narr.digital/book/99.0000/9783739880303</DOIWebsiteLink>
1096 <DOIStructuralType>Abstraction</DOIStructuralType>
1097 <DOIMode>Abstract</DOIMode>
1098 <RegistrantName>Narr Francke Attempto</RegistrantName>
1099 <MonographicPublication>
1100 <MonographicWork>
1101 <WorkIdentifier>
1102 <WorkIDType>06</WorkIDType>
1103 <IDValue>10.2357/9783739880303-105</IDValue>
1104 </WorkIdentifier>
1105 <Title language="ger">
1106 <TitleType>01</TitleType>
1107 <TitleText>Bodenseeschifferpatent kompakt</TitleText>
1108 <Subtitle>Motorboot und Segelboot</Subtitle>
1109 </Title>
1110 </MonographicWork>
1111 </MonographicPublication>
1112 <ContentItem>
1113 <Title language="ger">
1114 <TitleType>01</TitleType>
1115 <TitleText>Kapitel 11: Sturmwarndienst und Seenotrettung</TitleText>
1116 </Title>
1117 <Contributor>
1118 <ContributorRole>A01</ContributorRole>
1119 <PersonNameInverted>Wassermann, Matthias</PersonNameInverted>
1120 </Contributor>
1121 <Language>
1122 <LanguageRole>01</LanguageRole>
1123 <LanguageCode>ger</LanguageCode>
1124 </Language>
1125 <PublicationDate>2020</PublicationDate>
1126 <CopyrightStatement>
1127 <CopyrightYear>2020</CopyrightYear>
1128 <CopyrightOwner>
1129 <CorporateName>Narr Francke Attempto Verlag GmbH + Co. KG</CorporateName>
1130 </CopyrightOwner>
1131 </CopyrightStatement>
1132 </ContentItem>
1133 </DOIMonographChapterWork>
1134</ONIXDOIMonographChapterWorkRegistrationMessage>"""
1136 medra_responses = {
1137 "10.3233/ds-210053": medra_article_xml,
1138 "10.23775/20221026": medra_book_xml,
1139 "10.17426/58141": medra_series_xml,
1140 "10.2357/9783739880303-105": medra_chapter_xml,
1141 }
1143 def medra_callback(request):
1144 url = request.url.lower()
1145 for doi, xml in medra_responses.items():
1146 if doi.lower() in url:
1147 return (200, {}, xml)
1148 return (404, {}, "")
1150 rsps.add_callback(
1151 responses.GET,
1152 re.compile(r"https://api\.medra\.org/metadata/.*"),
1153 callback=medra_callback,
1154 content_type="application/xml",
1155 )
1158def _register_url_mocks(rsps: responses.RequestsMock) -> None:
1159 valid_urls = {
1160 "datacite.org",
1161 "opencitations.net",
1162 "nih.gov",
1163 "it.wikipedia.org/wiki/Muro%20di%20Berlino",
1164 "it.wikipedia.org/wiki/Muro di Berlino",
1165 }
1166 invalid_paths = {"invalid_url", "not%20a%20real%20page", "not a real page"}
1168 def url_callback(request):
1169 url = request.url.lower()
1170 for invalid in invalid_paths:
1171 if invalid in url:
1172 return (404, {}, "")
1173 for valid in valid_urls:
1174 if valid.lower() in url:
1175 return (200, {}, "<html><body>Valid page</body></html>")
1176 return (404, {}, "")
1178 for domain in ["datacite.org", "opencitations.net", "nih.gov", "it.wikipedia.org"]:
1179 rsps.add_callback(
1180 responses.GET,
1181 re.compile(rf"https?://(www\.)?{re.escape(domain)}.*"),
1182 callback=url_callback,
1183 content_type="text/html",
1184 )