scitex 2.17.0__py3-none-any.whl → 2.17.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- scitex/_dev/__init__.py +122 -0
- scitex/_dev/_config.py +391 -0
- scitex/_dev/_dashboard/__init__.py +11 -0
- scitex/_dev/_dashboard/_app.py +89 -0
- scitex/_dev/_dashboard/_routes.py +169 -0
- scitex/_dev/_dashboard/_scripts.py +301 -0
- scitex/_dev/_dashboard/_styles.py +205 -0
- scitex/_dev/_dashboard/_templates.py +117 -0
- scitex/_dev/_dashboard/static/version-dashboard-favicon.svg +12 -0
- scitex/_dev/_ecosystem.py +109 -0
- scitex/_dev/_github.py +360 -0
- scitex/_dev/_mcp/__init__.py +11 -0
- scitex/_dev/_mcp/handlers.py +182 -0
- scitex/_dev/_ssh.py +332 -0
- scitex/_dev/_versions.py +272 -0
- scitex/_mcp_tools/__init__.py +2 -0
- scitex/_mcp_tools/dev.py +186 -0
- scitex/audio/_audio_check.py +84 -41
- scitex/cli/capture.py +45 -22
- scitex/cli/dev.py +494 -0
- scitex/cli/main.py +2 -0
- scitex/cli/stats.py +48 -20
- scitex/cli/verify.py +33 -36
- scitex/plt/__init__.py +16 -6
- scitex/scholar/url_finder/.tmp/open_url/KNOWN_RESOLVERS.py +462 -0
- scitex/scholar/url_finder/.tmp/open_url/README.md +223 -0
- scitex/scholar/url_finder/.tmp/open_url/_DOIToURLResolver.py +694 -0
- scitex/scholar/url_finder/.tmp/open_url/_OpenURLResolver.py +1160 -0
- scitex/scholar/url_finder/.tmp/open_url/_ResolverLinkFinder.py +344 -0
- scitex/scholar/url_finder/.tmp/open_url/__init__.py +24 -0
- scitex/template/__init__.py +18 -1
- scitex/template/clone_research_minimal.py +111 -0
- scitex/verify/README.md +0 -12
- scitex/verify/__init__.py +0 -4
- scitex/verify/_visualize.py +0 -4
- scitex/verify/_viz/__init__.py +0 -18
- {scitex-2.17.0.dist-info → scitex-2.17.3.dist-info}/METADATA +2 -1
- {scitex-2.17.0.dist-info → scitex-2.17.3.dist-info}/RECORD +41 -49
- scitex/dev/plt/data/mpl/PLOTTING_FUNCTIONS.yaml +0 -90
- scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES.yaml +0 -1571
- scitex/dev/plt/data/mpl/PLOTTING_SIGNATURES_DETAILED.yaml +0 -6262
- scitex/dev/plt/data/mpl/SIGNATURES_FLATTENED.yaml +0 -1274
- scitex/dev/plt/data/mpl/dir_ax.txt +0 -459
- scitex/scholar/data/.gitkeep +0 -0
- scitex/scholar/data/README.md +0 -44
- scitex/scholar/data/bib_files/bibliography.bib +0 -1952
- scitex/scholar/data/bib_files/neurovista.bib +0 -277
- scitex/scholar/data/bib_files/neurovista_enriched.bib +0 -441
- scitex/scholar/data/bib_files/neurovista_enriched_enriched.bib +0 -441
- scitex/scholar/data/bib_files/neurovista_processed.bib +0 -338
- scitex/scholar/data/bib_files/openaccess.bib +0 -89
- scitex/scholar/data/bib_files/pac-seizure_prediction_enriched.bib +0 -2178
- scitex/scholar/data/bib_files/pac.bib +0 -698
- scitex/scholar/data/bib_files/pac_enriched.bib +0 -1061
- scitex/scholar/data/bib_files/pac_processed.bib +0 -0
- scitex/scholar/data/bib_files/pac_titles.txt +0 -75
- scitex/scholar/data/bib_files/paywalled.bib +0 -98
- scitex/scholar/data/bib_files/related-papers-by-coauthors.bib +0 -58
- scitex/scholar/data/bib_files/related-papers-by-coauthors_enriched.bib +0 -87
- scitex/scholar/data/bib_files/seizure_prediction.bib +0 -694
- scitex/scholar/data/bib_files/seizure_prediction_processed.bib +0 -0
- scitex/scholar/data/bib_files/test_complete_enriched.bib +0 -437
- scitex/scholar/data/bib_files/test_final_enriched.bib +0 -437
- scitex/scholar/data/bib_files/test_seizure.bib +0 -46
- scitex/scholar/data/impact_factor/JCR_IF_2022.xlsx +0 -0
- scitex/scholar/data/impact_factor/JCR_IF_2024.db +0 -0
- scitex/scholar/data/impact_factor/JCR_IF_2024.xlsx +0 -0
- scitex/scholar/data/impact_factor/JCR_IF_2024_v01.db +0 -0
- scitex/scholar/data/impact_factor.db +0 -0
- scitex/verify/_viz/_plotly.py +0 -193
- {scitex-2.17.0.dist-info → scitex-2.17.3.dist-info}/WHEEL +0 -0
- {scitex-2.17.0.dist-info → scitex-2.17.3.dist-info}/entry_points.txt +0 -0
- {scitex-2.17.0.dist-info → scitex-2.17.3.dist-info}/licenses/LICENSE +0 -0
scitex/cli/verify.py
CHANGED
|
@@ -262,13 +262,12 @@ def verify_chain_cmd(target_file, verbose, mermaid, as_json):
|
|
|
262
262
|
@click.option("--session", "-s", help="Session ID to visualize")
|
|
263
263
|
@click.option("--file", "-f", "target_file", help="Target file to trace chain")
|
|
264
264
|
@click.option("--title", "-t", default="Verification DAG", help="Title for output")
|
|
265
|
-
|
|
266
|
-
def render_cmd(output_path, session, target_file, title, plotly):
|
|
265
|
+
def render_cmd(output_path, session, target_file, title):
|
|
267
266
|
"""
|
|
268
267
|
Render verification DAG to file (HTML, PNG, SVG, or Mermaid).
|
|
269
268
|
|
|
270
269
|
The output format is determined by the file extension:
|
|
271
|
-
- .html: Interactive HTML
|
|
270
|
+
- .html: Interactive HTML with Mermaid.js
|
|
272
271
|
- .png: PNG image
|
|
273
272
|
- .svg: SVG image
|
|
274
273
|
- .mmd: Raw Mermaid code
|
|
@@ -276,7 +275,6 @@ def render_cmd(output_path, session, target_file, title, plotly):
|
|
|
276
275
|
\b
|
|
277
276
|
Examples:
|
|
278
277
|
scitex verify render dag.html --file ./results/fig.png
|
|
279
|
-
scitex verify render dag.html --file ./results/fig.png --plotly
|
|
280
278
|
scitex verify render dag.png --session 2025Y-11M-18D-09h12m03s
|
|
281
279
|
"""
|
|
282
280
|
try:
|
|
@@ -284,24 +282,14 @@ def render_cmd(output_path, session, target_file, title, plotly):
|
|
|
284
282
|
click.secho("Error: Specify --session or --file", fg="red", err=True)
|
|
285
283
|
sys.exit(1)
|
|
286
284
|
|
|
287
|
-
|
|
288
|
-
from scitex.verify import render_plotly_dag
|
|
285
|
+
from scitex.verify import render_dag
|
|
289
286
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
else:
|
|
297
|
-
from scitex.verify import render_dag
|
|
298
|
-
|
|
299
|
-
result_path = render_dag(
|
|
300
|
-
output_path=output_path,
|
|
301
|
-
session_id=session,
|
|
302
|
-
target_file=target_file,
|
|
303
|
-
title=title,
|
|
304
|
-
)
|
|
287
|
+
result_path = render_dag(
|
|
288
|
+
output_path=output_path,
|
|
289
|
+
session_id=session,
|
|
290
|
+
target_file=target_file,
|
|
291
|
+
title=title,
|
|
292
|
+
)
|
|
305
293
|
click.secho(f"Rendered to: {result_path}", fg="green")
|
|
306
294
|
|
|
307
295
|
except Exception as e:
|
|
@@ -433,25 +421,34 @@ def mcp(ctx):
|
|
|
433
421
|
|
|
434
422
|
|
|
435
423
|
@mcp.command("list-tools")
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
List available MCP tools for verification.
|
|
439
|
-
|
|
440
|
-
\b
|
|
441
|
-
Example:
|
|
442
|
-
scitex verify mcp list-tools
|
|
443
|
-
"""
|
|
424
|
+
@click.option("-v", "--verbose", count=True, help="-v params, -vv returns")
|
|
425
|
+
def list_tools(verbose):
|
|
426
|
+
"""List available MCP tools for verification."""
|
|
444
427
|
click.secho("Verify MCP Tools", fg="cyan", bold=True)
|
|
445
428
|
click.echo()
|
|
429
|
+
# (name, desc, params, returns)
|
|
446
430
|
tools = [
|
|
447
|
-
("verify_list", "List
|
|
448
|
-
("verify_run", "Verify a
|
|
449
|
-
("verify_chain", "Verify dependency chain
|
|
450
|
-
("verify_status", "Show
|
|
451
|
-
("verify_stats", "Show database statistics"),
|
|
431
|
+
("verify_list", "List tracked runs", "limit=50, status_filter=None", "JSON"),
|
|
432
|
+
("verify_run", "Verify a session run", "session_or_path: str", "JSON"),
|
|
433
|
+
("verify_chain", "Verify dependency chain", "target_file: str", "JSON"),
|
|
434
|
+
("verify_status", "Show status (like git status)", "", "JSON"),
|
|
435
|
+
("verify_stats", "Show database statistics", "", "JSON"),
|
|
436
|
+
(
|
|
437
|
+
"verify_mermaid",
|
|
438
|
+
"Generate Mermaid DAG",
|
|
439
|
+
"session_id=None, target_file=None",
|
|
440
|
+
"str",
|
|
441
|
+
),
|
|
452
442
|
]
|
|
453
|
-
for name, desc in tools:
|
|
454
|
-
click.
|
|
443
|
+
for name, desc, params, returns in tools:
|
|
444
|
+
click.secho(f" {name}", fg="green", bold=True, nl=False)
|
|
445
|
+
click.echo(f": {desc}")
|
|
446
|
+
if verbose >= 1 and params:
|
|
447
|
+
click.echo(f" params: {params}")
|
|
448
|
+
if verbose >= 2:
|
|
449
|
+
click.echo(f" returns: {returns}")
|
|
450
|
+
if verbose >= 1:
|
|
451
|
+
click.echo()
|
|
455
452
|
|
|
456
453
|
|
|
457
454
|
@verify.command("list-python-apis")
|
scitex/plt/__init__.py
CHANGED
|
@@ -75,8 +75,8 @@ if _FIGRECIPE_AVAILABLE:
|
|
|
75
75
|
from figrecipe import (
|
|
76
76
|
compose,
|
|
77
77
|
crop,
|
|
78
|
-
edit,
|
|
79
78
|
extract_data,
|
|
79
|
+
gui,
|
|
80
80
|
info,
|
|
81
81
|
list_presets,
|
|
82
82
|
load_style,
|
|
@@ -87,11 +87,17 @@ if _FIGRECIPE_AVAILABLE:
|
|
|
87
87
|
validate,
|
|
88
88
|
)
|
|
89
89
|
|
|
90
|
+
# Backward compatibility alias
|
|
91
|
+
edit = gui
|
|
92
|
+
|
|
90
93
|
# Internal imports (not part of figrecipe public API)
|
|
91
94
|
from figrecipe._api._notebook import enable_svg
|
|
92
95
|
from figrecipe._api._seaborn_proxy import sns
|
|
93
96
|
from figrecipe._api._style_manager import STYLE, apply_style
|
|
94
|
-
from figrecipe._composition import align_panels,
|
|
97
|
+
from figrecipe._composition import align_panels, align_smart, distribute_panels
|
|
98
|
+
|
|
99
|
+
# Backward compatibility alias
|
|
100
|
+
smart_align = align_smart
|
|
95
101
|
from figrecipe._graph_presets import get_preset as get_graph_preset
|
|
96
102
|
from figrecipe._graph_presets import list_presets as list_graph_presets
|
|
97
103
|
from figrecipe._graph_presets import register_preset as register_graph_preset
|
|
@@ -120,11 +126,13 @@ else:
|
|
|
120
126
|
validate = _not_available
|
|
121
127
|
extract_data = _not_available
|
|
122
128
|
info = _not_available
|
|
123
|
-
|
|
129
|
+
gui = _not_available
|
|
130
|
+
edit = _not_available # Backward compatibility alias
|
|
124
131
|
compose = _not_available
|
|
125
132
|
align_panels = _not_available
|
|
126
133
|
distribute_panels = _not_available
|
|
127
|
-
|
|
134
|
+
align_smart = _not_available
|
|
135
|
+
smart_align = _not_available # Backward compatibility alias
|
|
128
136
|
sns = None
|
|
129
137
|
enable_svg = _not_available
|
|
130
138
|
get_graph_preset = _not_available
|
|
@@ -438,7 +446,8 @@ __all__ = [
|
|
|
438
446
|
"validate",
|
|
439
447
|
"extract_data",
|
|
440
448
|
"info",
|
|
441
|
-
"
|
|
449
|
+
"gui",
|
|
450
|
+
"edit", # Backward compatibility alias for gui
|
|
442
451
|
# Style management
|
|
443
452
|
"STYLE",
|
|
444
453
|
"load_style",
|
|
@@ -449,7 +458,8 @@ __all__ = [
|
|
|
449
458
|
"compose",
|
|
450
459
|
"align_panels",
|
|
451
460
|
"distribute_panels",
|
|
452
|
-
"
|
|
461
|
+
"align_smart",
|
|
462
|
+
"smart_align", # Backward compatibility alias for align_smart
|
|
453
463
|
# Graph visualization
|
|
454
464
|
"draw_graph",
|
|
455
465
|
"get_graph_preset",
|
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Time-stamp: "2025-08-01 13:15:00"
|
|
4
|
+
# Author: Claude
|
|
5
|
+
# File: KNOWN_RESOLVERS.py
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
Known OpenURL resolvers from various institutions worldwide.
|
|
9
|
+
|
|
10
|
+
This module contains a curated list of OpenURL resolvers used by
|
|
11
|
+
academic institutions for accessing scholarly content.
|
|
12
|
+
|
|
13
|
+
Sources:
|
|
14
|
+
- Zotero OpenURL Resolver Directory: https://www.zotero.org/openurl_resolvers
|
|
15
|
+
- Individual institution library websites
|
|
16
|
+
- Common resolver patterns
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from typing import Dict, List, Optional
|
|
20
|
+
|
|
21
|
+
# Major OpenURL resolver vendors
|
|
22
|
+
RESOLVER_VENDORS = {
|
|
23
|
+
"ExLibris": {
|
|
24
|
+
"patterns": ["sfx", "exlibrisgroup.com"],
|
|
25
|
+
"description": "Ex Libris SFX resolver (very common)"
|
|
26
|
+
},
|
|
27
|
+
"SerialsSolutions": {
|
|
28
|
+
"patterns": ["serialssolutions.com", "360link"],
|
|
29
|
+
"description": "ProQuest SerialsSolutions 360 Link"
|
|
30
|
+
},
|
|
31
|
+
"EBSCO": {
|
|
32
|
+
"patterns": ["ebscohost.com/openurlresolver", "linkssource.ebsco.com"],
|
|
33
|
+
"description": "EBSCO Full Text Finder"
|
|
34
|
+
},
|
|
35
|
+
"OCLC": {
|
|
36
|
+
"patterns": ["worldcat.org", "oclc.org"],
|
|
37
|
+
"description": "OCLC WorldCat resolver"
|
|
38
|
+
},
|
|
39
|
+
"Ovid": {
|
|
40
|
+
"patterns": ["ovid.com", "linksolver"],
|
|
41
|
+
"description": "Ovid LinkSolver"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# Known institutional OpenURL resolvers
|
|
46
|
+
KNOWN_RESOLVERS: Dict[str, Dict[str, str]] = {
|
|
47
|
+
# United States
|
|
48
|
+
"Harvard University": {
|
|
49
|
+
"url": "https://sfx.hul.harvard.edu/sfx_local",
|
|
50
|
+
"country": "US",
|
|
51
|
+
"vendor": "ExLibris"
|
|
52
|
+
},
|
|
53
|
+
"MIT": {
|
|
54
|
+
"url": "https://owens.mit.edu/sfx_local",
|
|
55
|
+
"country": "US",
|
|
56
|
+
"vendor": "ExLibris"
|
|
57
|
+
},
|
|
58
|
+
"Stanford University": {
|
|
59
|
+
"url": "https://stanford.idm.oclc.org/login?url=",
|
|
60
|
+
"country": "US",
|
|
61
|
+
"vendor": "OCLC"
|
|
62
|
+
},
|
|
63
|
+
"Yale University": {
|
|
64
|
+
"url": "https://yale.idm.oclc.org/login?url=",
|
|
65
|
+
"country": "US",
|
|
66
|
+
"vendor": "OCLC"
|
|
67
|
+
},
|
|
68
|
+
"University of California, Berkeley": {
|
|
69
|
+
"url": "https://ucelinks.cdlib.org:8443/sfx_ucb",
|
|
70
|
+
"country": "US",
|
|
71
|
+
"vendor": "ExLibris"
|
|
72
|
+
},
|
|
73
|
+
"UCLA": {
|
|
74
|
+
"url": "https://ucelinks.cdlib.org:8443/sfx_ucla",
|
|
75
|
+
"country": "US",
|
|
76
|
+
"vendor": "ExLibris"
|
|
77
|
+
},
|
|
78
|
+
"Columbia University": {
|
|
79
|
+
"url": "https://resolver.library.columbia.edu/openurl",
|
|
80
|
+
"country": "US",
|
|
81
|
+
"vendor": "SerialsSolutions"
|
|
82
|
+
},
|
|
83
|
+
"Princeton University": {
|
|
84
|
+
"url": "https://princeton.idm.oclc.org/login?url=",
|
|
85
|
+
"country": "US",
|
|
86
|
+
"vendor": "OCLC"
|
|
87
|
+
},
|
|
88
|
+
"University of Chicago": {
|
|
89
|
+
"url": "https://proxy.uchicago.edu/login?url=",
|
|
90
|
+
"country": "US",
|
|
91
|
+
"vendor": "Custom"
|
|
92
|
+
},
|
|
93
|
+
"Johns Hopkins": {
|
|
94
|
+
"url": "https://openurl.library.jhu.edu",
|
|
95
|
+
"country": "US",
|
|
96
|
+
"vendor": "Custom"
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
# United Kingdom
|
|
100
|
+
"University of Oxford": {
|
|
101
|
+
"url": "https://fs.oxfordjournals.org/openurl",
|
|
102
|
+
"country": "UK",
|
|
103
|
+
"vendor": "Custom"
|
|
104
|
+
},
|
|
105
|
+
"University of Cambridge": {
|
|
106
|
+
"url": "https://cambridge.idm.oclc.org/login?url=",
|
|
107
|
+
"country": "UK",
|
|
108
|
+
"vendor": "OCLC"
|
|
109
|
+
},
|
|
110
|
+
"Imperial College London": {
|
|
111
|
+
"url": "https://imperial.idm.oclc.org/login?url=",
|
|
112
|
+
"country": "UK",
|
|
113
|
+
"vendor": "OCLC"
|
|
114
|
+
},
|
|
115
|
+
"UCL": {
|
|
116
|
+
"url": "https://ucl.idm.oclc.org/login?url=",
|
|
117
|
+
"country": "UK",
|
|
118
|
+
"vendor": "OCLC"
|
|
119
|
+
},
|
|
120
|
+
"University of Edinburgh": {
|
|
121
|
+
"url": "https://discovered.ed.ac.uk/openurl",
|
|
122
|
+
"country": "UK",
|
|
123
|
+
"vendor": "Custom"
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
# Canada
|
|
127
|
+
"University of Toronto": {
|
|
128
|
+
"url": "https://myaccess.library.utoronto.ca/login?url=",
|
|
129
|
+
"country": "CA",
|
|
130
|
+
"vendor": "Custom"
|
|
131
|
+
},
|
|
132
|
+
"McGill University": {
|
|
133
|
+
"url": "https://mcgill.on.worldcat.org/atoztitles/link",
|
|
134
|
+
"country": "CA",
|
|
135
|
+
"vendor": "OCLC"
|
|
136
|
+
},
|
|
137
|
+
"University of British Columbia": {
|
|
138
|
+
"url": "https://ubc.summon.serialssolutions.com/link",
|
|
139
|
+
"country": "CA",
|
|
140
|
+
"vendor": "SerialsSolutions"
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
# Australia
|
|
144
|
+
"University of Melbourne": {
|
|
145
|
+
"url": "https://unimelb.hosted.exlibrisgroup.com/sfxlcl41",
|
|
146
|
+
"country": "AU",
|
|
147
|
+
"vendor": "ExLibris"
|
|
148
|
+
},
|
|
149
|
+
"University of Sydney": {
|
|
150
|
+
"url": "https://ap01.alma.exlibrisgroup.com/view/uresolver/61USYD_INST/openurl",
|
|
151
|
+
"country": "AU",
|
|
152
|
+
"vendor": "ExLibris"
|
|
153
|
+
},
|
|
154
|
+
"Australian National University": {
|
|
155
|
+
"url": "https://anu.hosted.exlibrisgroup.com/primo-explore/openurl",
|
|
156
|
+
"country": "AU",
|
|
157
|
+
"vendor": "ExLibris"
|
|
158
|
+
},
|
|
159
|
+
"University of Queensland": {
|
|
160
|
+
"url": "https://uq.summon.serialssolutions.com/link",
|
|
161
|
+
"country": "AU",
|
|
162
|
+
"vendor": "SerialsSolutions"
|
|
163
|
+
},
|
|
164
|
+
"Monash University": {
|
|
165
|
+
"url": "https://monash.hosted.exlibrisgroup.com/sfx_local",
|
|
166
|
+
"country": "AU",
|
|
167
|
+
"vendor": "ExLibris"
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
# Germany
|
|
171
|
+
"Max Planck Society": {
|
|
172
|
+
"url": "http://sfx.mpg.de/sfx_local",
|
|
173
|
+
"country": "DE",
|
|
174
|
+
"vendor": "ExLibris"
|
|
175
|
+
},
|
|
176
|
+
"University of Munich (LMU)": {
|
|
177
|
+
"url": "https://sfx.bib.uni-muenchen.de/sfx_lmu",
|
|
178
|
+
"country": "DE",
|
|
179
|
+
"vendor": "ExLibris"
|
|
180
|
+
},
|
|
181
|
+
"Heidelberg University": {
|
|
182
|
+
"url": "https://sfx.bib.uni-heidelberg.de/sfx_heidelberg",
|
|
183
|
+
"country": "DE",
|
|
184
|
+
"vendor": "ExLibris"
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
# Netherlands
|
|
188
|
+
"University of Amsterdam": {
|
|
189
|
+
"url": "https://vu-nl.idm.oclc.org/login?url=",
|
|
190
|
+
"country": "NL",
|
|
191
|
+
"vendor": "OCLC"
|
|
192
|
+
},
|
|
193
|
+
"Delft University of Technology": {
|
|
194
|
+
"url": "https://tudelft.idm.oclc.org/login?url=",
|
|
195
|
+
"country": "NL",
|
|
196
|
+
"vendor": "OCLC"
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
# France
|
|
200
|
+
"Sorbonne University": {
|
|
201
|
+
"url": "https://accesdistant.sorbonne-universite.fr/login?url=",
|
|
202
|
+
"country": "FR",
|
|
203
|
+
"vendor": "Custom"
|
|
204
|
+
},
|
|
205
|
+
"École Polytechnique": {
|
|
206
|
+
"url": "https://portail.polytechnique.edu/openurl",
|
|
207
|
+
"country": "FR",
|
|
208
|
+
"vendor": "Custom"
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
# Switzerland
|
|
212
|
+
"ETH Zurich": {
|
|
213
|
+
"url": "https://www.library.ethz.ch/openurl",
|
|
214
|
+
"country": "CH",
|
|
215
|
+
"vendor": "Custom"
|
|
216
|
+
},
|
|
217
|
+
"EPFL": {
|
|
218
|
+
"url": "https://sfx.epfl.ch/sfx_local",
|
|
219
|
+
"country": "CH",
|
|
220
|
+
"vendor": "ExLibris"
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
# Japan
|
|
224
|
+
"University of Tokyo": {
|
|
225
|
+
"url": "https://vs2ga4mq9g.search.serialssolutions.com",
|
|
226
|
+
"country": "JP",
|
|
227
|
+
"vendor": "SerialsSolutions"
|
|
228
|
+
},
|
|
229
|
+
"Kyoto University": {
|
|
230
|
+
"url": "https://kuline.kulib.kyoto-u.ac.jp/portal/openurl",
|
|
231
|
+
"country": "JP",
|
|
232
|
+
"vendor": "Custom"
|
|
233
|
+
},
|
|
234
|
+
|
|
235
|
+
# Singapore
|
|
236
|
+
"National University of Singapore": {
|
|
237
|
+
"url": "https://libproxy.nus.edu.sg/login?url=",
|
|
238
|
+
"country": "SG",
|
|
239
|
+
"vendor": "Custom"
|
|
240
|
+
},
|
|
241
|
+
"Nanyang Technological University": {
|
|
242
|
+
"url": "https://ap01.alma.exlibrisgroup.com/view/uresolver/65NTU_INST/openurl",
|
|
243
|
+
"country": "SG",
|
|
244
|
+
"vendor": "ExLibris"
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
# China
|
|
248
|
+
"Tsinghua University": {
|
|
249
|
+
"url": "http://sfx.lib.tsinghua.edu.cn/sfx_local",
|
|
250
|
+
"country": "CN",
|
|
251
|
+
"vendor": "ExLibris"
|
|
252
|
+
},
|
|
253
|
+
"Peking University": {
|
|
254
|
+
"url": "http://sfx.lib.pku.edu.cn/sfx_pku",
|
|
255
|
+
"country": "CN",
|
|
256
|
+
"vendor": "ExLibris"
|
|
257
|
+
},
|
|
258
|
+
|
|
259
|
+
# South Korea
|
|
260
|
+
"Seoul National University": {
|
|
261
|
+
"url": "https://sfx.snu.ac.kr/sfx_local",
|
|
262
|
+
"country": "KR",
|
|
263
|
+
"vendor": "ExLibris"
|
|
264
|
+
},
|
|
265
|
+
"KAIST": {
|
|
266
|
+
"url": "https://library.kaist.ac.kr/openurl",
|
|
267
|
+
"country": "KR",
|
|
268
|
+
"vendor": "Custom"
|
|
269
|
+
},
|
|
270
|
+
|
|
271
|
+
# Brazil
|
|
272
|
+
"University of São Paulo": {
|
|
273
|
+
"url": "http://www.buscaintegrada.usp.br/openurl",
|
|
274
|
+
"country": "BR",
|
|
275
|
+
"vendor": "Custom"
|
|
276
|
+
},
|
|
277
|
+
|
|
278
|
+
# Mexico
|
|
279
|
+
"UNAM": {
|
|
280
|
+
"url": "https://pbidi.unam.mx/login?url=",
|
|
281
|
+
"country": "MX",
|
|
282
|
+
"vendor": "Custom"
|
|
283
|
+
},
|
|
284
|
+
|
|
285
|
+
# India
|
|
286
|
+
"IIT Delhi": {
|
|
287
|
+
"url": "https://libproxy.iitd.ac.in/login?url=",
|
|
288
|
+
"country": "IN",
|
|
289
|
+
"vendor": "Custom"
|
|
290
|
+
},
|
|
291
|
+
"Indian Institute of Science": {
|
|
292
|
+
"url": "https://library.iisc.ac.in/openurl",
|
|
293
|
+
"country": "IN",
|
|
294
|
+
"vendor": "Custom"
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
# Generic OpenURL resolver patterns
|
|
299
|
+
GENERIC_PATTERNS = [
|
|
300
|
+
# ExLibris SFX patterns
|
|
301
|
+
r"https?://[^/]+/sfx[^/]*",
|
|
302
|
+
r"https?://sfx\.[^/]+",
|
|
303
|
+
r"https?://[^/]+\.exlibrisgroup\.com",
|
|
304
|
+
|
|
305
|
+
# SerialsSolutions patterns
|
|
306
|
+
r"https?://[^/]+\.serialssolutions\.com",
|
|
307
|
+
r"https?://[^/]+/360link",
|
|
308
|
+
|
|
309
|
+
# OCLC patterns
|
|
310
|
+
r"https?://[^/]+\.idm\.oclc\.org",
|
|
311
|
+
r"https?://[^/]+\.worldcat\.org",
|
|
312
|
+
|
|
313
|
+
# Common proxy patterns
|
|
314
|
+
r"https?://[^/]+/login\?url=",
|
|
315
|
+
r"https?://libproxy\.[^/]+",
|
|
316
|
+
r"https?://proxy\.[^/]+",
|
|
317
|
+
|
|
318
|
+
# OpenURL patterns
|
|
319
|
+
r"https?://[^/]+/openurl",
|
|
320
|
+
r"https?://[^/]+/openurlresolver",
|
|
321
|
+
]
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def get_resolver_by_institution(institution_name: str) -> Optional[Dict[str, str]]:
|
|
325
|
+
"""
|
|
326
|
+
Get OpenURL resolver information by institution name.
|
|
327
|
+
|
|
328
|
+
Args:
|
|
329
|
+
institution_name: Name of the institution
|
|
330
|
+
|
|
331
|
+
Returns:
|
|
332
|
+
Dict with 'url', 'country', and 'vendor' if found, None otherwise
|
|
333
|
+
"""
|
|
334
|
+
# Try exact match first
|
|
335
|
+
if institution_name in KNOWN_RESOLVERS:
|
|
336
|
+
return KNOWN_RESOLVERS[institution_name].copy()
|
|
337
|
+
|
|
338
|
+
# Try case-insensitive match
|
|
339
|
+
institution_lower = institution_name.lower()
|
|
340
|
+
for name, info in KNOWN_RESOLVERS.items():
|
|
341
|
+
if name.lower() == institution_lower:
|
|
342
|
+
return info.copy()
|
|
343
|
+
|
|
344
|
+
# Try partial match
|
|
345
|
+
for name, info in KNOWN_RESOLVERS.items():
|
|
346
|
+
if institution_lower in name.lower() or name.lower() in institution_lower:
|
|
347
|
+
return info.copy()
|
|
348
|
+
|
|
349
|
+
return None
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def get_resolvers_by_country(country_code: str) -> Dict[str, Dict[str, str]]:
|
|
353
|
+
"""
|
|
354
|
+
Get all OpenURL resolvers for a specific country.
|
|
355
|
+
|
|
356
|
+
Args:
|
|
357
|
+
country_code: Two-letter country code (e.g., 'US', 'UK', 'AU')
|
|
358
|
+
|
|
359
|
+
Returns:
|
|
360
|
+
Dict of institution names to resolver info
|
|
361
|
+
"""
|
|
362
|
+
country_code = country_code.upper()
|
|
363
|
+
return {
|
|
364
|
+
name: info
|
|
365
|
+
for name, info in KNOWN_RESOLVERS.items()
|
|
366
|
+
if info.get('country') == country_code
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def get_resolvers_by_vendor(vendor_name: str) -> Dict[str, Dict[str, str]]:
|
|
371
|
+
"""
|
|
372
|
+
Get all OpenURL resolvers using a specific vendor.
|
|
373
|
+
|
|
374
|
+
Args:
|
|
375
|
+
vendor_name: Vendor name (e.g., 'ExLibris', 'OCLC')
|
|
376
|
+
|
|
377
|
+
Returns:
|
|
378
|
+
Dict of institution names to resolver info
|
|
379
|
+
"""
|
|
380
|
+
return {
|
|
381
|
+
name: info
|
|
382
|
+
for name, info in KNOWN_RESOLVERS.items()
|
|
383
|
+
if info.get('vendor', '').lower() == vendor_name.lower()
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def validate_resolver_url(url: str) -> bool:
|
|
388
|
+
"""
|
|
389
|
+
Check if a URL looks like a valid OpenURL resolver.
|
|
390
|
+
|
|
391
|
+
Args:
|
|
392
|
+
url: URL to validate
|
|
393
|
+
|
|
394
|
+
Returns:
|
|
395
|
+
True if URL matches known resolver patterns
|
|
396
|
+
"""
|
|
397
|
+
import re
|
|
398
|
+
|
|
399
|
+
# Check against known resolver URLs
|
|
400
|
+
for info in KNOWN_RESOLVERS.values():
|
|
401
|
+
if url.startswith(info['url']):
|
|
402
|
+
return True
|
|
403
|
+
|
|
404
|
+
# Check against generic patterns
|
|
405
|
+
for pattern in GENERIC_PATTERNS:
|
|
406
|
+
if re.match(pattern, url):
|
|
407
|
+
return True
|
|
408
|
+
|
|
409
|
+
return False
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def get_all_resolvers() -> List[Dict[str, str]]:
|
|
413
|
+
"""
|
|
414
|
+
Get all known resolvers as a list.
|
|
415
|
+
|
|
416
|
+
Returns:
|
|
417
|
+
List of dicts with 'name', 'url', 'country', 'vendor'
|
|
418
|
+
"""
|
|
419
|
+
return [
|
|
420
|
+
{
|
|
421
|
+
'name': name,
|
|
422
|
+
'url': info['url'],
|
|
423
|
+
'country': info.get('country', 'Unknown'),
|
|
424
|
+
'vendor': info.get('vendor', 'Unknown')
|
|
425
|
+
}
|
|
426
|
+
for name, info in KNOWN_RESOLVERS.items()
|
|
427
|
+
]
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
# Common test DOIs for different publishers
|
|
431
|
+
TEST_DOIS = {
|
|
432
|
+
"Nature": "10.1038/nature12373",
|
|
433
|
+
"Science": "10.1126/science.1234567",
|
|
434
|
+
"Cell": "10.1016/j.cell.2020.01.001",
|
|
435
|
+
"Elsevier": "10.1016/j.neuroimage.2020.116584",
|
|
436
|
+
"Wiley": "10.1111/jnc.15327",
|
|
437
|
+
"Springer": "10.1007/s00401-021-02283-6",
|
|
438
|
+
"Oxford": "10.1093/brain/awaa123",
|
|
439
|
+
"IEEE": "10.1109/TPAMI.2020.2984611",
|
|
440
|
+
"ACS": "10.1021/acs.jmedchem.0c00606",
|
|
441
|
+
"PNAS": "10.1073/pnas.1921909117"
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
if __name__ == "__main__":
|
|
446
|
+
# Example usage
|
|
447
|
+
print(f"Total known resolvers: {len(KNOWN_RESOLVERS)}")
|
|
448
|
+
print(f"\nCountries represented: {len(set(info['country'] for info in KNOWN_RESOLVERS.values()))}")
|
|
449
|
+
print(f"Vendors: {set(info.get('vendor', 'Unknown') for info in KNOWN_RESOLVERS.values())}")
|
|
450
|
+
|
|
451
|
+
# Example: Find resolver for an institution
|
|
452
|
+
resolver = get_resolver_by_institution("Harvard")
|
|
453
|
+
if resolver:
|
|
454
|
+
print(f"\nHarvard resolver: {resolver['url']}")
|
|
455
|
+
|
|
456
|
+
# Example: Get all US resolvers
|
|
457
|
+
us_resolvers = get_resolvers_by_country("US")
|
|
458
|
+
print(f"\nUS institutions with resolvers: {len(us_resolvers)}")
|
|
459
|
+
|
|
460
|
+
# Example: Get all ExLibris resolvers
|
|
461
|
+
exlibris = get_resolvers_by_vendor("ExLibris")
|
|
462
|
+
print(f"Institutions using ExLibris SFX: {len(exlibris)}")
|