scitex 2.14.0__py3-none-any.whl → 2.15.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/__init__.py +71 -17
- scitex/_env_loader.py +156 -0
- scitex/_mcp_resources/__init__.py +37 -0
- scitex/_mcp_resources/_cheatsheet.py +135 -0
- scitex/_mcp_resources/_figrecipe.py +138 -0
- scitex/_mcp_resources/_formats.py +102 -0
- scitex/_mcp_resources/_modules.py +337 -0
- scitex/_mcp_resources/_session.py +149 -0
- scitex/_mcp_tools/__init__.py +4 -0
- scitex/_mcp_tools/audio.py +66 -0
- scitex/_mcp_tools/diagram.py +11 -95
- scitex/_mcp_tools/introspect.py +210 -0
- scitex/_mcp_tools/plt.py +260 -305
- scitex/_mcp_tools/scholar.py +74 -0
- scitex/_mcp_tools/social.py +27 -0
- scitex/_mcp_tools/template.py +24 -0
- scitex/_mcp_tools/writer.py +17 -210
- scitex/ai/_gen_ai/_PARAMS.py +10 -7
- scitex/ai/classification/reporters/_SingleClassificationReporter.py +45 -1603
- scitex/ai/classification/reporters/_mixins/__init__.py +36 -0
- scitex/ai/classification/reporters/_mixins/_constants.py +67 -0
- scitex/ai/classification/reporters/_mixins/_cv_summary.py +387 -0
- scitex/ai/classification/reporters/_mixins/_feature_importance.py +119 -0
- scitex/ai/classification/reporters/_mixins/_metrics.py +275 -0
- scitex/ai/classification/reporters/_mixins/_plotting.py +179 -0
- scitex/ai/classification/reporters/_mixins/_reports.py +153 -0
- scitex/ai/classification/reporters/_mixins/_storage.py +160 -0
- scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +30 -1550
- scitex/ai/classification/timeseries/_sliding_window_core.py +467 -0
- scitex/ai/classification/timeseries/_sliding_window_plotting.py +369 -0
- scitex/audio/README.md +40 -36
- scitex/audio/__init__.py +129 -61
- scitex/audio/_branding.py +185 -0
- scitex/audio/_mcp/__init__.py +32 -0
- scitex/audio/_mcp/handlers.py +59 -6
- scitex/audio/_mcp/speak_handlers.py +238 -0
- scitex/audio/_relay.py +225 -0
- scitex/audio/_tts.py +18 -10
- scitex/audio/engines/base.py +17 -10
- scitex/audio/engines/elevenlabs_engine.py +7 -2
- scitex/audio/mcp_server.py +228 -75
- scitex/canvas/README.md +1 -1
- scitex/canvas/editor/_dearpygui/__init__.py +25 -0
- scitex/canvas/editor/_dearpygui/_editor.py +147 -0
- scitex/canvas/editor/_dearpygui/_handlers.py +476 -0
- scitex/canvas/editor/_dearpygui/_panels/__init__.py +17 -0
- scitex/canvas/editor/_dearpygui/_panels/_control.py +119 -0
- scitex/canvas/editor/_dearpygui/_panels/_element_controls.py +190 -0
- scitex/canvas/editor/_dearpygui/_panels/_preview.py +43 -0
- scitex/canvas/editor/_dearpygui/_panels/_sections.py +390 -0
- scitex/canvas/editor/_dearpygui/_plotting.py +187 -0
- scitex/canvas/editor/_dearpygui/_rendering.py +504 -0
- scitex/canvas/editor/_dearpygui/_selection.py +295 -0
- scitex/canvas/editor/_dearpygui/_state.py +93 -0
- scitex/canvas/editor/_dearpygui/_utils.py +61 -0
- scitex/canvas/editor/flask_editor/_core/__init__.py +27 -0
- scitex/canvas/editor/flask_editor/_core/_bbox_extraction.py +200 -0
- scitex/canvas/editor/flask_editor/_core/_editor.py +173 -0
- scitex/canvas/editor/flask_editor/_core/_export_helpers.py +353 -0
- scitex/canvas/editor/flask_editor/_core/_routes_basic.py +190 -0
- scitex/canvas/editor/flask_editor/_core/_routes_export.py +332 -0
- scitex/canvas/editor/flask_editor/_core/_routes_panels.py +252 -0
- scitex/canvas/editor/flask_editor/_core/_routes_save.py +218 -0
- scitex/canvas/editor/flask_editor/_core.py +25 -1684
- scitex/canvas/editor/flask_editor/templates/__init__.py +32 -70
- scitex/cli/__init__.py +38 -43
- scitex/cli/audio.py +160 -41
- scitex/cli/capture.py +133 -20
- scitex/cli/introspect.py +488 -0
- scitex/cli/main.py +200 -109
- scitex/cli/mcp.py +60 -34
- scitex/cli/plt.py +414 -0
- scitex/cli/repro.py +15 -8
- scitex/cli/resource.py +15 -8
- scitex/cli/scholar/__init__.py +154 -8
- scitex/cli/scholar/_crossref_scitex.py +296 -0
- scitex/cli/scholar/_fetch.py +25 -3
- scitex/cli/social.py +355 -0
- scitex/cli/stats.py +136 -11
- scitex/cli/template.py +129 -12
- scitex/cli/tex.py +15 -8
- scitex/cli/writer.py +49 -299
- scitex/cloud/__init__.py +41 -2
- scitex/config/README.md +1 -1
- scitex/config/__init__.py +16 -2
- scitex/config/_env_registry.py +256 -0
- scitex/context/__init__.py +22 -0
- scitex/dev/__init__.py +20 -1
- scitex/diagram/__init__.py +42 -19
- scitex/diagram/mcp_server.py +13 -125
- scitex/gen/__init__.py +50 -14
- scitex/gen/_list_packages.py +4 -4
- scitex/introspect/__init__.py +82 -0
- scitex/introspect/_call_graph.py +303 -0
- scitex/introspect/_class_hierarchy.py +163 -0
- scitex/introspect/_core.py +41 -0
- scitex/introspect/_docstring.py +131 -0
- scitex/introspect/_examples.py +113 -0
- scitex/introspect/_imports.py +271 -0
- scitex/{gen/_inspect_module.py → introspect/_list_api.py} +48 -56
- scitex/introspect/_mcp/__init__.py +41 -0
- scitex/introspect/_mcp/handlers.py +233 -0
- scitex/introspect/_members.py +155 -0
- scitex/introspect/_resolve.py +89 -0
- scitex/introspect/_signature.py +131 -0
- scitex/introspect/_source.py +80 -0
- scitex/introspect/_type_hints.py +172 -0
- scitex/io/_save.py +1 -2
- scitex/io/bundle/README.md +1 -1
- scitex/logging/_formatters.py +19 -9
- scitex/mcp_server.py +98 -5
- scitex/os/__init__.py +4 -0
- scitex/{gen → os}/_check_host.py +4 -5
- scitex/plt/__init__.py +245 -550
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin/_wrappers.py +5 -10
- scitex/plt/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
- scitex/plt/gallery/README.md +1 -1
- scitex/plt/utils/_hitmap/__init__.py +82 -0
- scitex/plt/utils/_hitmap/_artist_extraction.py +343 -0
- scitex/plt/utils/_hitmap/_color_application.py +346 -0
- scitex/plt/utils/_hitmap/_color_conversion.py +121 -0
- scitex/plt/utils/_hitmap/_constants.py +40 -0
- scitex/plt/utils/_hitmap/_hitmap_core.py +334 -0
- scitex/plt/utils/_hitmap/_path_extraction.py +357 -0
- scitex/plt/utils/_hitmap/_query.py +113 -0
- scitex/plt/utils/_hitmap.py +46 -1616
- scitex/plt/utils/_metadata/__init__.py +80 -0
- scitex/plt/utils/_metadata/_artists/__init__.py +25 -0
- scitex/plt/utils/_metadata/_artists/_base.py +195 -0
- scitex/plt/utils/_metadata/_artists/_collections.py +356 -0
- scitex/plt/utils/_metadata/_artists/_extract.py +57 -0
- scitex/plt/utils/_metadata/_artists/_images.py +80 -0
- scitex/plt/utils/_metadata/_artists/_lines.py +261 -0
- scitex/plt/utils/_metadata/_artists/_patches.py +247 -0
- scitex/plt/utils/_metadata/_artists/_text.py +106 -0
- scitex/plt/utils/_metadata/_csv.py +416 -0
- scitex/plt/utils/_metadata/_detect.py +225 -0
- scitex/plt/utils/_metadata/_legend.py +127 -0
- scitex/plt/utils/_metadata/_rounding.py +117 -0
- scitex/plt/utils/_metadata/_verification.py +202 -0
- scitex/schema/README.md +1 -1
- scitex/scholar/__init__.py +8 -0
- scitex/scholar/_mcp/crossref_handlers.py +265 -0
- scitex/scholar/core/Scholar.py +63 -1700
- scitex/scholar/core/_mixins/__init__.py +36 -0
- scitex/scholar/core/_mixins/_enrichers.py +270 -0
- scitex/scholar/core/_mixins/_library_handlers.py +100 -0
- scitex/scholar/core/_mixins/_loaders.py +103 -0
- scitex/scholar/core/_mixins/_pdf_download.py +375 -0
- scitex/scholar/core/_mixins/_pipeline.py +312 -0
- scitex/scholar/core/_mixins/_project_handlers.py +125 -0
- scitex/scholar/core/_mixins/_savers.py +69 -0
- scitex/scholar/core/_mixins/_search.py +103 -0
- scitex/scholar/core/_mixins/_services.py +88 -0
- scitex/scholar/core/_mixins/_url_finding.py +105 -0
- scitex/scholar/crossref_scitex.py +367 -0
- scitex/scholar/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
- scitex/scholar/examples/00_run_all.sh +120 -0
- scitex/scholar/jobs/_executors.py +27 -3
- scitex/scholar/pdf_download/ScholarPDFDownloader.py +38 -416
- scitex/scholar/pdf_download/_cli.py +154 -0
- scitex/scholar/pdf_download/strategies/__init__.py +11 -8
- scitex/scholar/pdf_download/strategies/manual_download_fallback.py +80 -3
- scitex/scholar/pipelines/ScholarPipelineBibTeX.py +73 -121
- scitex/scholar/pipelines/ScholarPipelineParallel.py +80 -138
- scitex/scholar/pipelines/ScholarPipelineSingle.py +43 -63
- scitex/scholar/pipelines/_single_steps.py +71 -36
- scitex/scholar/storage/_LibraryManager.py +97 -1695
- scitex/scholar/storage/_mixins/__init__.py +30 -0
- scitex/scholar/storage/_mixins/_bibtex_handlers.py +128 -0
- scitex/scholar/storage/_mixins/_library_operations.py +218 -0
- scitex/scholar/storage/_mixins/_metadata_conversion.py +226 -0
- scitex/scholar/storage/_mixins/_paper_saving.py +456 -0
- scitex/scholar/storage/_mixins/_resolution.py +376 -0
- scitex/scholar/storage/_mixins/_storage_helpers.py +121 -0
- scitex/scholar/storage/_mixins/_symlink_handlers.py +226 -0
- scitex/security/README.md +3 -3
- scitex/session/README.md +1 -1
- scitex/session/__init__.py +26 -7
- scitex/session/_decorator.py +1 -1
- scitex/sh/README.md +1 -1
- scitex/sh/__init__.py +7 -4
- scitex/social/__init__.py +155 -0
- scitex/social/docs/EXTERNAL_PACKAGE_BRANDING.md +149 -0
- scitex/stats/_mcp/_handlers/__init__.py +31 -0
- scitex/stats/_mcp/_handlers/_corrections.py +113 -0
- scitex/stats/_mcp/_handlers/_descriptive.py +78 -0
- scitex/stats/_mcp/_handlers/_effect_size.py +106 -0
- scitex/stats/_mcp/_handlers/_format.py +94 -0
- scitex/stats/_mcp/_handlers/_normality.py +110 -0
- scitex/stats/_mcp/_handlers/_posthoc.py +224 -0
- scitex/stats/_mcp/_handlers/_power.py +247 -0
- scitex/stats/_mcp/_handlers/_recommend.py +102 -0
- scitex/stats/_mcp/_handlers/_run_test.py +279 -0
- scitex/stats/_mcp/_handlers/_stars.py +48 -0
- scitex/stats/_mcp/handlers.py +19 -1171
- scitex/stats/auto/_stat_style.py +175 -0
- scitex/stats/auto/_style_definitions.py +411 -0
- scitex/stats/auto/_styles.py +22 -620
- scitex/stats/descriptive/__init__.py +11 -8
- scitex/stats/descriptive/_ci.py +39 -0
- scitex/stats/power/_power.py +15 -4
- scitex/str/__init__.py +2 -1
- scitex/str/_title_case.py +63 -0
- scitex/template/README.md +1 -1
- scitex/template/__init__.py +25 -10
- scitex/template/_code_templates.py +147 -0
- scitex/template/_mcp/handlers.py +81 -0
- scitex/template/_mcp/tool_schemas.py +55 -0
- scitex/template/_templates/__init__.py +51 -0
- scitex/template/_templates/audio.py +233 -0
- scitex/template/_templates/canvas.py +312 -0
- scitex/template/_templates/capture.py +268 -0
- scitex/template/_templates/config.py +43 -0
- scitex/template/_templates/diagram.py +294 -0
- scitex/template/_templates/io.py +107 -0
- scitex/template/_templates/module.py +53 -0
- scitex/template/_templates/plt.py +202 -0
- scitex/template/_templates/scholar.py +267 -0
- scitex/template/_templates/session.py +130 -0
- scitex/template/_templates/session_minimal.py +43 -0
- scitex/template/_templates/session_plot.py +67 -0
- scitex/template/_templates/session_stats.py +77 -0
- scitex/template/_templates/stats.py +323 -0
- scitex/template/_templates/writer.py +296 -0
- scitex/template/clone_writer_directory.py +5 -5
- scitex/ui/_backends/_email.py +10 -2
- scitex/ui/_backends/_webhook.py +5 -1
- scitex/web/_search_pubmed.py +10 -6
- scitex/writer/README.md +1 -1
- scitex/writer/__init__.py +43 -34
- scitex/writer/_mcp/handlers.py +11 -744
- scitex/writer/_mcp/tool_schemas.py +5 -335
- scitex-2.15.3.dist-info/METADATA +667 -0
- {scitex-2.14.0.dist-info → scitex-2.15.3.dist-info}/RECORD +241 -120
- scitex/canvas/editor/flask_editor/templates/_scripts.py +0 -4933
- scitex/canvas/editor/flask_editor/templates/_styles.py +0 -1658
- scitex/diagram/_compile.py +0 -312
- scitex/diagram/_diagram.py +0 -355
- scitex/diagram/_mcp/__init__.py +0 -4
- scitex/diagram/_mcp/handlers.py +0 -400
- scitex/diagram/_mcp/tool_schemas.py +0 -157
- scitex/diagram/_presets.py +0 -173
- scitex/diagram/_schema.py +0 -182
- scitex/diagram/_split.py +0 -278
- scitex/gen/_ci.py +0 -12
- scitex/gen/_title_case.py +0 -89
- scitex/plt/_mcp/__init__.py +0 -4
- scitex/plt/_mcp/_handlers_annotation.py +0 -102
- scitex/plt/_mcp/_handlers_figure.py +0 -195
- scitex/plt/_mcp/_handlers_plot.py +0 -252
- scitex/plt/_mcp/_handlers_style.py +0 -219
- scitex/plt/_mcp/handlers.py +0 -74
- scitex/plt/_mcp/tool_schemas.py +0 -497
- scitex/plt/mcp_server.py +0 -231
- scitex/scholar/examples/SUGGESTIONS.md +0 -865
- scitex/scholar/examples/dev.py +0 -38
- scitex-2.14.0.dist-info/METADATA +0 -1238
- /scitex/{gen → context}/_detect_environment.py +0 -0
- /scitex/{gen → context}/_get_notebook_path.py +0 -0
- /scitex/{gen/_shell.py → sh/_shell_legacy.py} +0 -0
- {scitex-2.14.0.dist-info → scitex-2.15.3.dist-info}/WHEEL +0 -0
- {scitex-2.14.0.dist-info → scitex-2.15.3.dist-info}/entry_points.txt +0 -0
- {scitex-2.14.0.dist-info → scitex-2.15.3.dist-info}/licenses/LICENSE +0 -0
scitex/cli/plt.py
ADDED
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# Timestamp: 2026-01-25
|
|
3
|
+
# File: /home/ywatanabe/proj/scitex-python/src/scitex/cli/plt.py
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
SciTeX CLI - Plot Commands
|
|
7
|
+
|
|
8
|
+
Thin wrapper around figrecipe CLI for reproducible matplotlib figures.
|
|
9
|
+
All commands delegate to figrecipe for reproducibility.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import subprocess
|
|
13
|
+
import sys
|
|
14
|
+
|
|
15
|
+
import click
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _run_figrecipe(*args) -> int:
|
|
19
|
+
"""Run figrecipe CLI command."""
|
|
20
|
+
cmd = [sys.executable, "-m", "figrecipe"]
|
|
21
|
+
cmd.extend(args)
|
|
22
|
+
|
|
23
|
+
result = subprocess.run(cmd)
|
|
24
|
+
return result.returncode
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _check_figrecipe() -> bool:
|
|
28
|
+
"""Check if figrecipe is available."""
|
|
29
|
+
try:
|
|
30
|
+
import figrecipe # noqa: F401
|
|
31
|
+
|
|
32
|
+
return True
|
|
33
|
+
except ImportError:
|
|
34
|
+
return False
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@click.group(
|
|
38
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
39
|
+
invoke_without_command=True,
|
|
40
|
+
)
|
|
41
|
+
@click.option("--help-recursive", is_flag=True, help="Show help for all subcommands")
|
|
42
|
+
@click.pass_context
|
|
43
|
+
def plt(ctx, help_recursive):
|
|
44
|
+
"""
|
|
45
|
+
Plot and figure management (powered by figrecipe)
|
|
46
|
+
|
|
47
|
+
\b
|
|
48
|
+
Commands:
|
|
49
|
+
plot - Create figure from YAML/JSON spec
|
|
50
|
+
edit - Launch interactive GUI editor
|
|
51
|
+
compose - Combine multiple figures
|
|
52
|
+
crop - Crop whitespace from images
|
|
53
|
+
reproduce - Reproduce figure from recipe
|
|
54
|
+
validate - Validate recipe reproducibility
|
|
55
|
+
diagram - Create diagrams (flowcharts, etc.)
|
|
56
|
+
|
|
57
|
+
\b
|
|
58
|
+
Examples:
|
|
59
|
+
scitex plt plot spec.yaml -o fig.png
|
|
60
|
+
scitex plt edit
|
|
61
|
+
scitex plt compose a.png b.png -o combined.png
|
|
62
|
+
scitex plt reproduce recipe.yaml
|
|
63
|
+
|
|
64
|
+
\b
|
|
65
|
+
Note: Wraps figrecipe CLI. Run 'figrecipe --help' for full options.
|
|
66
|
+
"""
|
|
67
|
+
if not _check_figrecipe():
|
|
68
|
+
click.secho("Error: figrecipe not installed", fg="red", err=True)
|
|
69
|
+
click.echo("\nInstall with: pip install figrecipe")
|
|
70
|
+
ctx.exit(1)
|
|
71
|
+
|
|
72
|
+
if help_recursive:
|
|
73
|
+
from . import print_help_recursive
|
|
74
|
+
|
|
75
|
+
print_help_recursive(ctx, plt)
|
|
76
|
+
ctx.exit(0)
|
|
77
|
+
elif ctx.invoked_subcommand is None:
|
|
78
|
+
click.echo(ctx.get_help())
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@plt.command()
|
|
82
|
+
@click.argument("spec_file", type=click.Path(exists=True))
|
|
83
|
+
@click.option("-o", "--output", required=True, help="Output file path")
|
|
84
|
+
@click.option("--dpi", type=int, default=300, help="DPI for raster output")
|
|
85
|
+
@click.option("--no-recipe", is_flag=True, help="Don't save YAML recipe")
|
|
86
|
+
def plot(spec_file, output, dpi, no_recipe):
|
|
87
|
+
"""
|
|
88
|
+
Create a figure from a declarative YAML/JSON spec.
|
|
89
|
+
|
|
90
|
+
\b
|
|
91
|
+
Examples:
|
|
92
|
+
scitex plt plot spec.yaml -o fig.png
|
|
93
|
+
scitex plt plot spec.json -o fig.pdf --dpi 600
|
|
94
|
+
"""
|
|
95
|
+
args = ["plot", spec_file, "-o", output, "--dpi", str(dpi)]
|
|
96
|
+
if no_recipe:
|
|
97
|
+
args.append("--no-recipe")
|
|
98
|
+
sys.exit(_run_figrecipe(*args))
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@plt.command()
|
|
102
|
+
@click.argument("recipe_file", type=click.Path(exists=True), required=False)
|
|
103
|
+
def edit(recipe_file):
|
|
104
|
+
"""
|
|
105
|
+
Launch interactive GUI editor.
|
|
106
|
+
|
|
107
|
+
\b
|
|
108
|
+
Examples:
|
|
109
|
+
scitex plt edit # Open blank editor
|
|
110
|
+
scitex plt edit recipe.yaml # Open existing recipe
|
|
111
|
+
"""
|
|
112
|
+
args = ["edit"]
|
|
113
|
+
if recipe_file:
|
|
114
|
+
args.append(recipe_file)
|
|
115
|
+
sys.exit(_run_figrecipe(*args))
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@plt.command()
|
|
119
|
+
@click.argument("sources", nargs=-1, required=True, type=click.Path(exists=True))
|
|
120
|
+
@click.option("-o", "--output", required=True, help="Output file path")
|
|
121
|
+
@click.option(
|
|
122
|
+
"-l",
|
|
123
|
+
"--layout",
|
|
124
|
+
type=click.Choice(["horizontal", "vertical", "grid"]),
|
|
125
|
+
default="horizontal",
|
|
126
|
+
help="Layout mode",
|
|
127
|
+
)
|
|
128
|
+
@click.option("--gap", type=float, default=5, help="Gap between panels (mm)")
|
|
129
|
+
@click.option("--dpi", type=int, default=300, help="DPI for output")
|
|
130
|
+
@click.option("--no-labels", is_flag=True, help="Don't add panel labels (A, B, C)")
|
|
131
|
+
@click.option("--caption", help="Figure caption")
|
|
132
|
+
def compose(sources, output, layout, gap, dpi, no_labels, caption):
|
|
133
|
+
"""
|
|
134
|
+
Compose multiple figures into one.
|
|
135
|
+
|
|
136
|
+
\b
|
|
137
|
+
Examples:
|
|
138
|
+
scitex plt compose a.png b.png -o combined.png
|
|
139
|
+
scitex plt compose *.png -o fig.pdf --layout grid
|
|
140
|
+
scitex plt compose a.yaml b.yaml -o fig.png --gap 10
|
|
141
|
+
"""
|
|
142
|
+
args = ["compose"]
|
|
143
|
+
args.extend(sources)
|
|
144
|
+
args.extend(
|
|
145
|
+
["-o", output, "--layout", layout, "--gap", str(gap), "--dpi", str(dpi)]
|
|
146
|
+
)
|
|
147
|
+
if no_labels:
|
|
148
|
+
args.append("--no-labels")
|
|
149
|
+
if caption:
|
|
150
|
+
args.extend(["--caption", caption])
|
|
151
|
+
sys.exit(_run_figrecipe(*args))
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
@plt.command()
|
|
155
|
+
@click.argument("input_file", type=click.Path(exists=True))
|
|
156
|
+
@click.option("-o", "--output", help="Output file (default: overwrites input)")
|
|
157
|
+
@click.option("--margin", type=float, default=1, help="Margin to keep (mm)")
|
|
158
|
+
def crop(input_file, output, margin):
|
|
159
|
+
"""
|
|
160
|
+
Crop whitespace from an image.
|
|
161
|
+
|
|
162
|
+
\b
|
|
163
|
+
Examples:
|
|
164
|
+
scitex plt crop figure.png
|
|
165
|
+
scitex plt crop figure.png -o cropped.png --margin 2
|
|
166
|
+
"""
|
|
167
|
+
args = ["crop", input_file, "--margin", str(margin)]
|
|
168
|
+
if output:
|
|
169
|
+
args.extend(["-o", output])
|
|
170
|
+
sys.exit(_run_figrecipe(*args))
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@plt.command()
|
|
174
|
+
@click.argument("recipe_file", type=click.Path(exists=True))
|
|
175
|
+
@click.option("-o", "--output", help="Output file path")
|
|
176
|
+
@click.option(
|
|
177
|
+
"--format", "fmt", type=click.Choice(["png", "pdf", "svg"]), help="Output format"
|
|
178
|
+
)
|
|
179
|
+
@click.option("--dpi", type=int, default=300, help="DPI for raster output")
|
|
180
|
+
def reproduce(recipe_file, output, fmt, dpi):
|
|
181
|
+
"""
|
|
182
|
+
Reproduce a figure from a YAML recipe.
|
|
183
|
+
|
|
184
|
+
\b
|
|
185
|
+
Examples:
|
|
186
|
+
scitex plt reproduce recipe.yaml
|
|
187
|
+
scitex plt reproduce recipe.yaml -o new_fig.pdf
|
|
188
|
+
"""
|
|
189
|
+
args = ["reproduce", recipe_file, "--dpi", str(dpi)]
|
|
190
|
+
if output:
|
|
191
|
+
args.extend(["-o", output])
|
|
192
|
+
if fmt:
|
|
193
|
+
args.extend(["--format", fmt])
|
|
194
|
+
sys.exit(_run_figrecipe(*args))
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@plt.command()
|
|
198
|
+
@click.argument("recipe_file", type=click.Path(exists=True))
|
|
199
|
+
@click.option("--threshold", type=float, default=100, help="MSE threshold")
|
|
200
|
+
def validate(recipe_file, threshold):
|
|
201
|
+
"""
|
|
202
|
+
Validate that a recipe reproduces its original figure.
|
|
203
|
+
|
|
204
|
+
\b
|
|
205
|
+
Examples:
|
|
206
|
+
scitex plt validate recipe.yaml
|
|
207
|
+
scitex plt validate recipe.yaml --threshold 50
|
|
208
|
+
"""
|
|
209
|
+
args = ["validate", recipe_file, "--threshold", str(threshold)]
|
|
210
|
+
sys.exit(_run_figrecipe(*args))
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
@plt.command()
|
|
214
|
+
@click.argument("spec_file", type=click.Path(exists=True))
|
|
215
|
+
@click.option("-o", "--output", help="Output file path")
|
|
216
|
+
@click.option(
|
|
217
|
+
"--format", "fmt", type=click.Choice(["mermaid", "graphviz"]), default="mermaid"
|
|
218
|
+
)
|
|
219
|
+
def diagram(spec_file, output, fmt):
|
|
220
|
+
"""
|
|
221
|
+
Create diagrams (flowcharts, pipelines, etc.)
|
|
222
|
+
|
|
223
|
+
\b
|
|
224
|
+
Examples:
|
|
225
|
+
scitex plt diagram workflow.yaml
|
|
226
|
+
scitex plt diagram pipeline.yaml -o diagram.png --format graphviz
|
|
227
|
+
"""
|
|
228
|
+
args = ["diagram", spec_file, "--format", fmt]
|
|
229
|
+
if output:
|
|
230
|
+
args.extend(["-o", output])
|
|
231
|
+
sys.exit(_run_figrecipe(*args))
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
@plt.command()
|
|
235
|
+
@click.argument("recipe_file", type=click.Path(exists=True))
|
|
236
|
+
@click.option("-v", "--verbose", is_flag=True, help="Show detailed info")
|
|
237
|
+
def info(recipe_file, verbose):
|
|
238
|
+
"""
|
|
239
|
+
Show information about a recipe.
|
|
240
|
+
|
|
241
|
+
\b
|
|
242
|
+
Examples:
|
|
243
|
+
scitex plt info recipe.yaml
|
|
244
|
+
scitex plt info recipe.yaml --verbose
|
|
245
|
+
"""
|
|
246
|
+
args = ["info", recipe_file]
|
|
247
|
+
if verbose:
|
|
248
|
+
args.append("--verbose")
|
|
249
|
+
sys.exit(_run_figrecipe(*args))
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
@plt.command()
|
|
253
|
+
@click.argument("recipe_file", type=click.Path(exists=True))
|
|
254
|
+
@click.option("-o", "--output", help="Output file for extracted data")
|
|
255
|
+
def extract(recipe_file, output):
|
|
256
|
+
"""
|
|
257
|
+
Extract plotted data arrays from a recipe.
|
|
258
|
+
|
|
259
|
+
\b
|
|
260
|
+
Examples:
|
|
261
|
+
scitex plt extract recipe.yaml
|
|
262
|
+
scitex plt extract recipe.yaml -o data.json
|
|
263
|
+
"""
|
|
264
|
+
args = ["extract", recipe_file]
|
|
265
|
+
if output:
|
|
266
|
+
args.extend(["-o", output])
|
|
267
|
+
sys.exit(_run_figrecipe(*args))
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
@plt.command()
|
|
271
|
+
@click.argument("action", type=click.Choice(["list", "show", "set"]), default="list")
|
|
272
|
+
@click.argument("style_name", required=False)
|
|
273
|
+
def style(action, style_name):
|
|
274
|
+
"""
|
|
275
|
+
Manage figure styles and presets.
|
|
276
|
+
|
|
277
|
+
\b
|
|
278
|
+
Examples:
|
|
279
|
+
scitex plt style list # List available styles
|
|
280
|
+
scitex plt style show nature # Show style details
|
|
281
|
+
scitex plt style set publication # Set default style
|
|
282
|
+
"""
|
|
283
|
+
args = ["style", action]
|
|
284
|
+
if style_name:
|
|
285
|
+
args.append(style_name)
|
|
286
|
+
sys.exit(_run_figrecipe(*args))
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
@plt.command()
|
|
290
|
+
@click.option("--check", is_flag=True, help="Check font availability")
|
|
291
|
+
def fonts(check):
|
|
292
|
+
"""
|
|
293
|
+
List or check available fonts.
|
|
294
|
+
|
|
295
|
+
\b
|
|
296
|
+
Examples:
|
|
297
|
+
scitex plt fonts
|
|
298
|
+
scitex plt fonts --check
|
|
299
|
+
"""
|
|
300
|
+
args = ["fonts"]
|
|
301
|
+
if check:
|
|
302
|
+
args.append("--check")
|
|
303
|
+
sys.exit(_run_figrecipe(*args))
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
@plt.command()
|
|
307
|
+
@click.argument("input_file", type=click.Path(exists=True))
|
|
308
|
+
@click.option("-o", "--output", required=True, help="Output file path")
|
|
309
|
+
@click.option("--format", "fmt", help="Output format (inferred from extension)")
|
|
310
|
+
def convert(input_file, output, fmt):
|
|
311
|
+
"""
|
|
312
|
+
Convert between figure formats.
|
|
313
|
+
|
|
314
|
+
\b
|
|
315
|
+
Examples:
|
|
316
|
+
scitex plt convert fig.png -o fig.pdf
|
|
317
|
+
scitex plt convert fig.svg -o fig.png
|
|
318
|
+
"""
|
|
319
|
+
args = ["convert", input_file, "-o", output]
|
|
320
|
+
if fmt:
|
|
321
|
+
args.extend(["--format", fmt])
|
|
322
|
+
sys.exit(_run_figrecipe(*args))
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
@plt.group(invoke_without_command=True)
|
|
326
|
+
@click.pass_context
|
|
327
|
+
def mcp(ctx):
|
|
328
|
+
"""
|
|
329
|
+
MCP (Model Context Protocol) server operations
|
|
330
|
+
|
|
331
|
+
\b
|
|
332
|
+
Commands:
|
|
333
|
+
start - Start the MCP server
|
|
334
|
+
doctor - Check MCP server health
|
|
335
|
+
list-tools - List available MCP tools
|
|
336
|
+
info - Show MCP server information
|
|
337
|
+
install - Show installation instructions
|
|
338
|
+
|
|
339
|
+
\b
|
|
340
|
+
Examples:
|
|
341
|
+
scitex plt mcp start
|
|
342
|
+
scitex plt mcp doctor
|
|
343
|
+
"""
|
|
344
|
+
if ctx.invoked_subcommand is None:
|
|
345
|
+
click.echo(ctx.get_help())
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
@mcp.command()
|
|
349
|
+
@click.option("--host", default="0.0.0.0", help="Host for HTTP transport")
|
|
350
|
+
@click.option("--port", default=8087, type=int, help="Port for HTTP transport")
|
|
351
|
+
def start(host, port):
|
|
352
|
+
"""
|
|
353
|
+
Start the MCP server
|
|
354
|
+
|
|
355
|
+
\b
|
|
356
|
+
Example:
|
|
357
|
+
scitex plt mcp start
|
|
358
|
+
scitex plt mcp start --port 8087
|
|
359
|
+
"""
|
|
360
|
+
sys.exit(_run_figrecipe("mcp", "run", "--host", host, "--port", str(port)))
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
@mcp.command()
|
|
364
|
+
def doctor():
|
|
365
|
+
"""
|
|
366
|
+
Check MCP server health
|
|
367
|
+
|
|
368
|
+
\b
|
|
369
|
+
Example:
|
|
370
|
+
scitex plt mcp doctor
|
|
371
|
+
"""
|
|
372
|
+
sys.exit(_run_figrecipe("mcp", "doctor"))
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
@mcp.command("list-tools")
|
|
376
|
+
def list_tools_mcp():
|
|
377
|
+
"""
|
|
378
|
+
List available MCP tools
|
|
379
|
+
|
|
380
|
+
\b
|
|
381
|
+
Example:
|
|
382
|
+
scitex plt mcp list-tools
|
|
383
|
+
"""
|
|
384
|
+
sys.exit(_run_figrecipe("mcp", "list-tools"))
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
@mcp.command()
|
|
388
|
+
def info():
|
|
389
|
+
"""
|
|
390
|
+
Show MCP server information
|
|
391
|
+
|
|
392
|
+
\b
|
|
393
|
+
Example:
|
|
394
|
+
scitex plt mcp info
|
|
395
|
+
"""
|
|
396
|
+
sys.exit(_run_figrecipe("mcp", "info"))
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
@mcp.command()
|
|
400
|
+
def install():
|
|
401
|
+
"""
|
|
402
|
+
Show installation instructions
|
|
403
|
+
|
|
404
|
+
\b
|
|
405
|
+
Example:
|
|
406
|
+
scitex plt mcp install
|
|
407
|
+
"""
|
|
408
|
+
sys.exit(_run_figrecipe("mcp", "install"))
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
if __name__ == "__main__":
|
|
412
|
+
plt()
|
|
413
|
+
|
|
414
|
+
# EOF
|
scitex/cli/repro.py
CHANGED
|
@@ -10,8 +10,13 @@ import sys
|
|
|
10
10
|
import click
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
@click.group(
|
|
14
|
-
|
|
13
|
+
@click.group(
|
|
14
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
15
|
+
invoke_without_command=True,
|
|
16
|
+
)
|
|
17
|
+
@click.option("--help-recursive", is_flag=True, help="Show help for all subcommands")
|
|
18
|
+
@click.pass_context
|
|
19
|
+
def repro(ctx, help_recursive):
|
|
15
20
|
"""
|
|
16
21
|
Reproducibility utilities
|
|
17
22
|
|
|
@@ -29,20 +34,22 @@ def repro():
|
|
|
29
34
|
scitex repro hash data.npy # Hash array file
|
|
30
35
|
scitex repro seed 42 # Set random seed
|
|
31
36
|
"""
|
|
32
|
-
|
|
37
|
+
if help_recursive:
|
|
38
|
+
_print_help_recursive(ctx)
|
|
39
|
+
ctx.exit(0)
|
|
40
|
+
elif ctx.invoked_subcommand is None:
|
|
41
|
+
click.echo(ctx.get_help())
|
|
33
42
|
|
|
34
43
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def help_recursive(ctx):
|
|
38
|
-
"""Show help for all commands recursively."""
|
|
44
|
+
def _print_help_recursive(ctx):
|
|
45
|
+
"""Print help for all commands recursively."""
|
|
39
46
|
fake_parent = click.Context(click.Group(), info_name="scitex")
|
|
40
47
|
parent_ctx = click.Context(repro, info_name="repro", parent=fake_parent)
|
|
41
48
|
click.secho("━━━ scitex repro ━━━", fg="cyan", bold=True)
|
|
42
49
|
click.echo(repro.get_help(parent_ctx))
|
|
43
50
|
for name in sorted(repro.list_commands(ctx) or []):
|
|
44
51
|
cmd = repro.get_command(ctx, name)
|
|
45
|
-
if cmd is None
|
|
52
|
+
if cmd is None:
|
|
46
53
|
continue
|
|
47
54
|
click.echo()
|
|
48
55
|
click.secho(f"━━━ scitex repro {name} ━━━", fg="cyan", bold=True)
|
scitex/cli/resource.py
CHANGED
|
@@ -10,8 +10,13 @@ import sys
|
|
|
10
10
|
import click
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
@click.group(
|
|
14
|
-
|
|
13
|
+
@click.group(
|
|
14
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
15
|
+
invoke_without_command=True,
|
|
16
|
+
)
|
|
17
|
+
@click.option("--help-recursive", is_flag=True, help="Show help for all subcommands")
|
|
18
|
+
@click.pass_context
|
|
19
|
+
def resource(ctx, help_recursive):
|
|
15
20
|
"""
|
|
16
21
|
System resource monitoring
|
|
17
22
|
|
|
@@ -27,20 +32,22 @@ def resource():
|
|
|
27
32
|
scitex resource usage # Current CPU/memory/GPU usage
|
|
28
33
|
scitex resource monitor --interval 5
|
|
29
34
|
"""
|
|
30
|
-
|
|
35
|
+
if help_recursive:
|
|
36
|
+
_print_help_recursive(ctx)
|
|
37
|
+
ctx.exit(0)
|
|
38
|
+
elif ctx.invoked_subcommand is None:
|
|
39
|
+
click.echo(ctx.get_help())
|
|
31
40
|
|
|
32
41
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def help_recursive(ctx):
|
|
36
|
-
"""Show help for all commands recursively."""
|
|
42
|
+
def _print_help_recursive(ctx):
|
|
43
|
+
"""Print help for all commands recursively."""
|
|
37
44
|
fake_parent = click.Context(click.Group(), info_name="scitex")
|
|
38
45
|
parent_ctx = click.Context(resource, info_name="resource", parent=fake_parent)
|
|
39
46
|
click.secho("━━━ scitex resource ━━━", fg="cyan", bold=True)
|
|
40
47
|
click.echo(resource.get_help(parent_ctx))
|
|
41
48
|
for name in sorted(resource.list_commands(ctx) or []):
|
|
42
49
|
cmd = resource.get_command(ctx, name)
|
|
43
|
-
if cmd is None
|
|
50
|
+
if cmd is None:
|
|
44
51
|
continue
|
|
45
52
|
click.echo()
|
|
46
53
|
click.secho(f"━━━ scitex resource {name} ━━━", fg="cyan", bold=True)
|
scitex/cli/scholar/__init__.py
CHANGED
|
@@ -15,19 +15,31 @@ Usage:
|
|
|
15
15
|
scitex scholar config
|
|
16
16
|
scitex scholar jobs list
|
|
17
17
|
scitex scholar jobs status <job_id>
|
|
18
|
+
|
|
19
|
+
CrossRef database (167M+ papers via crossref-local):
|
|
20
|
+
scitex scholar crossref-scitex search "deep learning"
|
|
21
|
+
scitex scholar crossref-scitex get 10.1038/nature12373
|
|
22
|
+
scitex scholar crossref-scitex count "epilepsy seizure"
|
|
23
|
+
scitex scholar crossref-scitex info
|
|
18
24
|
"""
|
|
19
25
|
|
|
20
26
|
from __future__ import annotations
|
|
21
27
|
|
|
22
28
|
import click
|
|
23
29
|
|
|
30
|
+
from ._crossref_scitex import crossref_scitex
|
|
24
31
|
from ._fetch import fetch
|
|
25
32
|
from ._jobs import jobs
|
|
26
33
|
from ._library import config, library
|
|
27
34
|
|
|
28
35
|
|
|
29
|
-
@click.group(
|
|
30
|
-
|
|
36
|
+
@click.group(
|
|
37
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
38
|
+
invoke_without_command=True,
|
|
39
|
+
)
|
|
40
|
+
@click.option("--help-recursive", is_flag=True, help="Show help for all subcommands")
|
|
41
|
+
@click.pass_context
|
|
42
|
+
def scholar(ctx, help_recursive):
|
|
31
43
|
"""
|
|
32
44
|
Scientific paper management
|
|
33
45
|
|
|
@@ -41,13 +53,15 @@ def scholar():
|
|
|
41
53
|
scitex scholar library
|
|
42
54
|
scitex scholar jobs list
|
|
43
55
|
"""
|
|
44
|
-
|
|
56
|
+
if help_recursive:
|
|
57
|
+
_print_help_recursive(ctx)
|
|
58
|
+
ctx.exit(0)
|
|
59
|
+
elif ctx.invoked_subcommand is None:
|
|
60
|
+
click.echo(ctx.get_help())
|
|
45
61
|
|
|
46
62
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
def help_recursive(ctx):
|
|
50
|
-
"""Show help for all commands recursively."""
|
|
63
|
+
def _print_help_recursive(ctx):
|
|
64
|
+
"""Print help for all commands recursively."""
|
|
51
65
|
fake_parent = click.Context(click.Group(), info_name="scitex")
|
|
52
66
|
parent_ctx = click.Context(scholar, info_name="scholar", parent=fake_parent)
|
|
53
67
|
|
|
@@ -56,7 +70,7 @@ def help_recursive(ctx):
|
|
|
56
70
|
|
|
57
71
|
for name in sorted(scholar.list_commands(ctx) or []):
|
|
58
72
|
cmd = scholar.get_command(ctx, name)
|
|
59
|
-
if cmd is None
|
|
73
|
+
if cmd is None:
|
|
60
74
|
continue
|
|
61
75
|
click.echo()
|
|
62
76
|
click.secho(f"━━━ scitex scholar {name} ━━━", fg="cyan", bold=True)
|
|
@@ -79,6 +93,138 @@ def help_recursive(ctx):
|
|
|
79
93
|
click.echo(sub_cmd.get_help(sub_sub_ctx))
|
|
80
94
|
|
|
81
95
|
|
|
96
|
+
@scholar.group(invoke_without_command=True)
|
|
97
|
+
@click.pass_context
|
|
98
|
+
def mcp(ctx):
|
|
99
|
+
"""
|
|
100
|
+
MCP (Model Context Protocol) server operations
|
|
101
|
+
|
|
102
|
+
\b
|
|
103
|
+
Commands:
|
|
104
|
+
start - Start the MCP server
|
|
105
|
+
doctor - Check MCP server health
|
|
106
|
+
list-tools - List available MCP tools
|
|
107
|
+
|
|
108
|
+
\b
|
|
109
|
+
Examples:
|
|
110
|
+
scitex scholar mcp start
|
|
111
|
+
scitex scholar mcp list-tools
|
|
112
|
+
"""
|
|
113
|
+
if ctx.invoked_subcommand is None:
|
|
114
|
+
click.echo(ctx.get_help())
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@mcp.command()
|
|
118
|
+
@click.option(
|
|
119
|
+
"-t",
|
|
120
|
+
"--transport",
|
|
121
|
+
type=click.Choice(["stdio", "sse", "http"]),
|
|
122
|
+
default="stdio",
|
|
123
|
+
help="Transport protocol (default: stdio)",
|
|
124
|
+
)
|
|
125
|
+
@click.option("--host", default="0.0.0.0", help="Host for HTTP/SSE (default: 0.0.0.0)")
|
|
126
|
+
@click.option(
|
|
127
|
+
"--port", default=8097, type=int, help="Port for HTTP/SSE (default: 8097)"
|
|
128
|
+
)
|
|
129
|
+
def start(transport, host, port):
|
|
130
|
+
"""
|
|
131
|
+
Start the scholar MCP server
|
|
132
|
+
|
|
133
|
+
\b
|
|
134
|
+
Examples:
|
|
135
|
+
scitex scholar mcp start
|
|
136
|
+
scitex scholar mcp start -t http --port 8097
|
|
137
|
+
"""
|
|
138
|
+
import sys
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
from scitex.scholar.mcp_server import main as run_server
|
|
142
|
+
|
|
143
|
+
if transport != "stdio":
|
|
144
|
+
click.secho(f"Starting scholar MCP server ({transport})", fg="cyan")
|
|
145
|
+
click.echo(f" Host: {host}")
|
|
146
|
+
click.echo(f" Port: {port}")
|
|
147
|
+
|
|
148
|
+
run_server()
|
|
149
|
+
|
|
150
|
+
except ImportError as e:
|
|
151
|
+
click.secho(f"Error: {e}", fg="red", err=True)
|
|
152
|
+
click.echo("\nInstall dependencies: pip install fastmcp")
|
|
153
|
+
sys.exit(1)
|
|
154
|
+
except Exception as e:
|
|
155
|
+
click.secho(f"Error: {e}", fg="red", err=True)
|
|
156
|
+
sys.exit(1)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@mcp.command()
|
|
160
|
+
def doctor():
|
|
161
|
+
"""
|
|
162
|
+
Check MCP server health and dependencies
|
|
163
|
+
|
|
164
|
+
\b
|
|
165
|
+
Example:
|
|
166
|
+
scitex scholar mcp doctor
|
|
167
|
+
"""
|
|
168
|
+
click.secho("Scholar MCP Server Health Check", fg="cyan", bold=True)
|
|
169
|
+
click.echo()
|
|
170
|
+
|
|
171
|
+
click.echo("Checking FastMCP... ", nl=False)
|
|
172
|
+
try:
|
|
173
|
+
import fastmcp # noqa: F401
|
|
174
|
+
|
|
175
|
+
click.secho("OK", fg="green")
|
|
176
|
+
except ImportError:
|
|
177
|
+
click.secho("NOT INSTALLED", fg="red")
|
|
178
|
+
click.echo(" Install with: pip install fastmcp")
|
|
179
|
+
|
|
180
|
+
click.echo("Checking scholar module... ", nl=False)
|
|
181
|
+
try:
|
|
182
|
+
from scitex import scholar as _ # noqa: F401
|
|
183
|
+
|
|
184
|
+
click.secho("OK", fg="green")
|
|
185
|
+
except ImportError as e:
|
|
186
|
+
click.secho(f"FAIL ({e})", fg="red")
|
|
187
|
+
|
|
188
|
+
click.echo("Checking crossref-local... ", nl=False)
|
|
189
|
+
try:
|
|
190
|
+
import crossref_local # noqa: F401
|
|
191
|
+
|
|
192
|
+
click.secho("OK", fg="green")
|
|
193
|
+
except ImportError:
|
|
194
|
+
click.secho("NOT INSTALLED (optional)", fg="yellow")
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@mcp.command("list-tools")
|
|
198
|
+
def list_tools():
|
|
199
|
+
"""
|
|
200
|
+
List available MCP tools
|
|
201
|
+
|
|
202
|
+
\b
|
|
203
|
+
Example:
|
|
204
|
+
scitex scholar mcp list-tools
|
|
205
|
+
"""
|
|
206
|
+
click.secho("Scholar MCP Tools", fg="cyan", bold=True)
|
|
207
|
+
click.echo()
|
|
208
|
+
tools = [
|
|
209
|
+
("scholar_search_papers", "Search for papers by query"),
|
|
210
|
+
("scholar_resolve_dois", "Resolve DOIs to metadata"),
|
|
211
|
+
("scholar_enrich_bibtex", "Enrich BibTeX with abstracts/DOIs"),
|
|
212
|
+
("scholar_download_pdf", "Download PDF for a paper"),
|
|
213
|
+
("scholar_download_pdfs_batch", "Batch download PDFs"),
|
|
214
|
+
("scholar_get_library_status", "Get library status"),
|
|
215
|
+
("scholar_parse_bibtex", "Parse BibTeX file"),
|
|
216
|
+
("scholar_validate_pdfs", "Validate downloaded PDFs"),
|
|
217
|
+
("scholar_authenticate", "Authenticate with institution"),
|
|
218
|
+
("scholar_check_auth_status", "Check authentication status"),
|
|
219
|
+
("scholar_fetch_papers", "Fetch papers by DOIs"),
|
|
220
|
+
("scholar_crossref_search", "Search CrossRef database"),
|
|
221
|
+
("scholar_crossref_get", "Get paper by DOI from CrossRef"),
|
|
222
|
+
]
|
|
223
|
+
for name, desc in tools:
|
|
224
|
+
click.echo(f" {name}: {desc}")
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
scholar.add_command(crossref_scitex)
|
|
82
228
|
scholar.add_command(fetch)
|
|
83
229
|
scholar.add_command(library)
|
|
84
230
|
scholar.add_command(config)
|