scitex 2.14.0__py3-none-any.whl → 2.15.2__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 +244 -0
- scitex/_mcp_tools/template.py +24 -0
- scitex/_mcp_tools/writer.py +21 -204
- 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 +76 -27
- scitex/cli/capture.py +13 -20
- scitex/cli/introspect.py +481 -0
- scitex/cli/main.py +200 -109
- scitex/cli/mcp.py +60 -34
- scitex/cli/plt.py +357 -0
- scitex/cli/repro.py +15 -8
- scitex/cli/resource.py +15 -8
- scitex/cli/scholar/__init__.py +23 -8
- scitex/cli/scholar/_crossref_scitex.py +296 -0
- scitex/cli/scholar/_fetch.py +25 -3
- scitex/cli/social.py +314 -0
- scitex/cli/stats.py +15 -8
- scitex/cli/template.py +129 -12
- scitex/cli/tex.py +15 -8
- scitex/cli/writer.py +132 -8
- 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} +43 -54
- 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/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/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/_mcp/handlers.py +11 -744
- scitex/writer/_mcp/tool_schemas.py +5 -335
- scitex-2.15.2.dist-info/METADATA +648 -0
- {scitex-2.14.0.dist-info → scitex-2.15.2.dist-info}/RECORD +246 -150
- scitex/canvas/editor/flask_editor/templates/_scripts.py +0 -4933
- scitex/canvas/editor/flask_editor/templates/_styles.py +0 -1658
- 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/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/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/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.2.dist-info}/WHEEL +0 -0
- {scitex-2.14.0.dist-info → scitex-2.15.2.dist-info}/entry_points.txt +0 -0
- {scitex-2.14.0.dist-info → scitex-2.15.2.dist-info}/licenses/LICENSE +0 -0
scitex/cli/introspect.py
ADDED
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
SciTeX CLI - Introspection Commands
|
|
4
|
+
|
|
5
|
+
Provides IPython-like introspection for Python packages.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
import click
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@click.group(
|
|
15
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
16
|
+
invoke_without_command=True,
|
|
17
|
+
)
|
|
18
|
+
@click.option("--help-recursive", is_flag=True, help="Show help for all subcommands")
|
|
19
|
+
@click.pass_context
|
|
20
|
+
def introspect(ctx, help_recursive):
|
|
21
|
+
"""
|
|
22
|
+
Python package introspection utilities
|
|
23
|
+
|
|
24
|
+
\b
|
|
25
|
+
IPython-like introspection for any Python package:
|
|
26
|
+
q - Function/class signature (like func?)
|
|
27
|
+
qq - Full source code (like func??)
|
|
28
|
+
dir - List module/class members (like dir())
|
|
29
|
+
api - Full module API tree
|
|
30
|
+
docstring - Extract docstrings
|
|
31
|
+
exports - Show __all__ exports
|
|
32
|
+
examples - Find usage examples
|
|
33
|
+
|
|
34
|
+
\b
|
|
35
|
+
Examples:
|
|
36
|
+
scitex introspect q scitex.plt.plot
|
|
37
|
+
scitex introspect qq scitex.stats.run_test --max-lines 50
|
|
38
|
+
scitex introspect dir scitex.plt --kind functions
|
|
39
|
+
scitex introspect api scitex --max-depth 2
|
|
40
|
+
"""
|
|
41
|
+
if help_recursive:
|
|
42
|
+
from . import print_help_recursive
|
|
43
|
+
|
|
44
|
+
print_help_recursive(ctx, introspect)
|
|
45
|
+
ctx.exit(0)
|
|
46
|
+
elif ctx.invoked_subcommand is None:
|
|
47
|
+
click.echo(ctx.get_help())
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@introspect.command()
|
|
51
|
+
@click.argument("dotted_path")
|
|
52
|
+
@click.option("--no-defaults", is_flag=True, help="Exclude default values")
|
|
53
|
+
@click.option("--no-annotations", is_flag=True, help="Exclude type annotations")
|
|
54
|
+
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
55
|
+
def q(dotted_path, no_defaults, no_annotations, as_json):
|
|
56
|
+
"""
|
|
57
|
+
Get function/class signature (like IPython's func?)
|
|
58
|
+
|
|
59
|
+
\b
|
|
60
|
+
Examples:
|
|
61
|
+
scitex introspect q scitex.plt.plot
|
|
62
|
+
scitex introspect q scitex.audio.speak --json
|
|
63
|
+
scitex introspect q json.dumps
|
|
64
|
+
"""
|
|
65
|
+
from scitex.introspect import q as get_q
|
|
66
|
+
|
|
67
|
+
result = get_q(
|
|
68
|
+
dotted_path,
|
|
69
|
+
include_defaults=not no_defaults,
|
|
70
|
+
include_annotations=not no_annotations,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
if not result.get("success", False):
|
|
74
|
+
click.secho(f"Error: {result.get('error', 'Unknown error')}", fg="red")
|
|
75
|
+
sys.exit(1)
|
|
76
|
+
|
|
77
|
+
if as_json:
|
|
78
|
+
click.echo(json.dumps(result, indent=2))
|
|
79
|
+
else:
|
|
80
|
+
click.secho(result["signature"], fg="green", bold=True)
|
|
81
|
+
if result.get("parameters"):
|
|
82
|
+
click.echo("\nParameters:")
|
|
83
|
+
for p in result["parameters"]:
|
|
84
|
+
line = f" {p['name']}"
|
|
85
|
+
if "annotation" in p:
|
|
86
|
+
line += f": {p['annotation']}"
|
|
87
|
+
if "default" in p:
|
|
88
|
+
line += f" = {p['default']}"
|
|
89
|
+
click.echo(line)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@introspect.command()
|
|
93
|
+
@click.argument("dotted_path")
|
|
94
|
+
@click.option("--max-lines", "-n", type=int, help="Limit output to N lines")
|
|
95
|
+
@click.option("--no-decorators", is_flag=True, help="Exclude decorator lines")
|
|
96
|
+
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
97
|
+
def qq(dotted_path, max_lines, no_decorators, as_json):
|
|
98
|
+
"""
|
|
99
|
+
Get source code of a Python object (like IPython's func??)
|
|
100
|
+
|
|
101
|
+
\b
|
|
102
|
+
Examples:
|
|
103
|
+
scitex introspect qq scitex.plt.plot
|
|
104
|
+
scitex introspect qq scitex.audio.speak --max-lines 50
|
|
105
|
+
"""
|
|
106
|
+
from scitex.introspect import qq as get_qq
|
|
107
|
+
|
|
108
|
+
result = get_qq(
|
|
109
|
+
dotted_path,
|
|
110
|
+
max_lines=max_lines,
|
|
111
|
+
include_decorators=not no_decorators,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
if not result.get("success", False):
|
|
115
|
+
click.secho(f"Error: {result.get('error', 'Unknown error')}", fg="red")
|
|
116
|
+
sys.exit(1)
|
|
117
|
+
|
|
118
|
+
if as_json:
|
|
119
|
+
click.echo(json.dumps(result, indent=2))
|
|
120
|
+
else:
|
|
121
|
+
click.secho(f"# File: {result['file']}:{result['line_start']}", fg="cyan")
|
|
122
|
+
click.secho(f"# Lines: {result['line_count']}", fg="cyan")
|
|
123
|
+
click.echo()
|
|
124
|
+
click.echo(result["source"])
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@introspect.command("dir")
|
|
128
|
+
@click.argument("dotted_path")
|
|
129
|
+
@click.option(
|
|
130
|
+
"--filter",
|
|
131
|
+
"-f",
|
|
132
|
+
type=click.Choice(["all", "public", "private", "dunder"]),
|
|
133
|
+
default="public",
|
|
134
|
+
help="Filter members",
|
|
135
|
+
)
|
|
136
|
+
@click.option(
|
|
137
|
+
"--kind",
|
|
138
|
+
"-k",
|
|
139
|
+
type=click.Choice(["all", "functions", "classes", "data", "modules"]),
|
|
140
|
+
help="Filter by type",
|
|
141
|
+
)
|
|
142
|
+
@click.option("--inherited", is_flag=True, help="Include inherited members (classes)")
|
|
143
|
+
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
144
|
+
def dir_cmd(dotted_path, filter, kind, inherited, as_json):
|
|
145
|
+
"""
|
|
146
|
+
List members of a module or class (like dir())
|
|
147
|
+
|
|
148
|
+
\b
|
|
149
|
+
Examples:
|
|
150
|
+
scitex introspect dir scitex.plt
|
|
151
|
+
scitex introspect dir scitex.audio --kind functions
|
|
152
|
+
scitex introspect dir scitex.plt.AxisWrapper --filter all
|
|
153
|
+
"""
|
|
154
|
+
from scitex.introspect import dir as get_dir
|
|
155
|
+
|
|
156
|
+
result = get_dir(
|
|
157
|
+
dotted_path,
|
|
158
|
+
filter=filter,
|
|
159
|
+
kind=kind,
|
|
160
|
+
include_inherited=inherited,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
if not result.get("success", False):
|
|
164
|
+
click.secho(f"Error: {result.get('error', 'Unknown error')}", fg="red")
|
|
165
|
+
sys.exit(1)
|
|
166
|
+
|
|
167
|
+
if as_json:
|
|
168
|
+
click.echo(json.dumps(result, indent=2))
|
|
169
|
+
else:
|
|
170
|
+
click.secho(f"Members of {dotted_path} ({result['count']}):", fg="cyan")
|
|
171
|
+
for m in result["members"]:
|
|
172
|
+
kind_str = click.style(f"[{m['kind']}]", fg="yellow")
|
|
173
|
+
name_str = click.style(m["name"], fg="green", bold=True)
|
|
174
|
+
summary = f" - {m['summary']}" if m["summary"] else ""
|
|
175
|
+
click.echo(f" {kind_str} {name_str}{summary}")
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@introspect.command()
|
|
179
|
+
@click.argument("dotted_path")
|
|
180
|
+
@click.option("--max-depth", "-d", type=int, default=5, help="Max recursion depth")
|
|
181
|
+
@click.option("--docstring", is_flag=True, help="Include docstrings")
|
|
182
|
+
@click.option("--root-only", is_flag=True, help="Show only root-level items")
|
|
183
|
+
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
184
|
+
def api(dotted_path, max_depth, docstring, root_only, as_json):
|
|
185
|
+
"""
|
|
186
|
+
List the full API tree of a module recursively
|
|
187
|
+
|
|
188
|
+
\b
|
|
189
|
+
Examples:
|
|
190
|
+
scitex introspect api scitex --max-depth 2
|
|
191
|
+
scitex introspect api scitex.plt --docstring
|
|
192
|
+
scitex introspect api scitex.audio --root-only
|
|
193
|
+
"""
|
|
194
|
+
from scitex.introspect import list_api
|
|
195
|
+
|
|
196
|
+
df = list_api(
|
|
197
|
+
dotted_path,
|
|
198
|
+
max_depth=max_depth,
|
|
199
|
+
docstring=docstring,
|
|
200
|
+
root_only=root_only,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
if as_json:
|
|
204
|
+
click.echo(json.dumps(df.to_dict(orient="records"), indent=2))
|
|
205
|
+
else:
|
|
206
|
+
click.secho(f"API tree of {dotted_path} ({len(df)} items):", fg="cyan")
|
|
207
|
+
for _, row in df.iterrows():
|
|
208
|
+
indent = " " * row["Depth"]
|
|
209
|
+
type_str = click.style(f"[{row['Type']}]", fg="yellow")
|
|
210
|
+
name = row["Name"].split(".")[-1]
|
|
211
|
+
name_str = click.style(name, fg="green", bold=True)
|
|
212
|
+
doc = f" - {row['Docstring'][:50]}..." if row.get("Docstring") else ""
|
|
213
|
+
click.echo(f"{indent}{type_str} {name_str}{doc}")
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
@introspect.command()
|
|
217
|
+
@click.argument("dotted_path")
|
|
218
|
+
@click.option(
|
|
219
|
+
"--format",
|
|
220
|
+
"-f",
|
|
221
|
+
type=click.Choice(["raw", "parsed", "summary"]),
|
|
222
|
+
default="raw",
|
|
223
|
+
help="Output format",
|
|
224
|
+
)
|
|
225
|
+
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
226
|
+
def docstring(dotted_path, format, as_json):
|
|
227
|
+
"""
|
|
228
|
+
Get docstring of a Python object
|
|
229
|
+
|
|
230
|
+
\b
|
|
231
|
+
Formats:
|
|
232
|
+
raw - Full docstring as-is
|
|
233
|
+
parsed - Parse into sections (summary, parameters, returns, etc.)
|
|
234
|
+
summary - First line/paragraph only
|
|
235
|
+
|
|
236
|
+
\b
|
|
237
|
+
Examples:
|
|
238
|
+
scitex introspect docstring scitex.plt.plot
|
|
239
|
+
scitex introspect docstring scitex.audio.speak --format parsed
|
|
240
|
+
"""
|
|
241
|
+
from scitex.introspect import get_docstring
|
|
242
|
+
|
|
243
|
+
result = get_docstring(dotted_path, format=format)
|
|
244
|
+
|
|
245
|
+
if not result.get("success", False):
|
|
246
|
+
click.secho(f"Error: {result.get('error', 'Unknown error')}", fg="red")
|
|
247
|
+
sys.exit(1)
|
|
248
|
+
|
|
249
|
+
if as_json:
|
|
250
|
+
click.echo(json.dumps(result, indent=2))
|
|
251
|
+
else:
|
|
252
|
+
click.echo(result["docstring"])
|
|
253
|
+
if format == "parsed" and result.get("sections"):
|
|
254
|
+
click.echo("\n--- Parsed Sections ---")
|
|
255
|
+
for key, value in result["sections"].items():
|
|
256
|
+
if value:
|
|
257
|
+
click.secho(f"\n[{key}]", fg="cyan", bold=True)
|
|
258
|
+
click.echo(value)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
@introspect.command()
|
|
262
|
+
@click.argument("dotted_path")
|
|
263
|
+
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
264
|
+
def exports(dotted_path, as_json):
|
|
265
|
+
"""
|
|
266
|
+
Get __all__ exports of a module
|
|
267
|
+
|
|
268
|
+
\b
|
|
269
|
+
Examples:
|
|
270
|
+
scitex introspect exports scitex.audio
|
|
271
|
+
scitex introspect exports scitex.plt
|
|
272
|
+
"""
|
|
273
|
+
from scitex.introspect import get_exports
|
|
274
|
+
|
|
275
|
+
result = get_exports(dotted_path)
|
|
276
|
+
|
|
277
|
+
if not result.get("success", False):
|
|
278
|
+
click.secho(f"Error: {result.get('error', 'Unknown error')}", fg="red")
|
|
279
|
+
sys.exit(1)
|
|
280
|
+
|
|
281
|
+
if as_json:
|
|
282
|
+
click.echo(json.dumps(result, indent=2))
|
|
283
|
+
else:
|
|
284
|
+
has_all = "defined" if result["has_all"] else "not defined (showing public)"
|
|
285
|
+
click.secho(f"__all__ is {has_all}", fg="cyan")
|
|
286
|
+
click.secho(f"Exports ({result['count']}):", fg="cyan")
|
|
287
|
+
for name in result["exports"]:
|
|
288
|
+
click.echo(f" {name}")
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
@introspect.command()
|
|
292
|
+
@click.argument("dotted_path")
|
|
293
|
+
@click.option("--search-paths", "-p", help="Comma-separated search paths")
|
|
294
|
+
@click.option("--max-results", "-n", type=int, default=10, help="Max examples")
|
|
295
|
+
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
296
|
+
def examples(dotted_path, search_paths, max_results, as_json):
|
|
297
|
+
"""
|
|
298
|
+
Find usage examples in tests/examples directories
|
|
299
|
+
|
|
300
|
+
\b
|
|
301
|
+
Examples:
|
|
302
|
+
scitex introspect examples scitex.plt.plot
|
|
303
|
+
scitex introspect examples scitex.audio.speak --max-results 5
|
|
304
|
+
"""
|
|
305
|
+
from scitex.introspect import find_examples
|
|
306
|
+
|
|
307
|
+
paths_list = None
|
|
308
|
+
if search_paths:
|
|
309
|
+
paths_list = [p.strip() for p in search_paths.split(",")]
|
|
310
|
+
|
|
311
|
+
result = find_examples(
|
|
312
|
+
dotted_path,
|
|
313
|
+
search_paths=paths_list,
|
|
314
|
+
max_results=max_results,
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
if not result.get("success", False):
|
|
318
|
+
click.secho(f"Error: {result.get('error', 'Unknown error')}", fg="red")
|
|
319
|
+
sys.exit(1)
|
|
320
|
+
|
|
321
|
+
if as_json:
|
|
322
|
+
click.echo(json.dumps(result, indent=2))
|
|
323
|
+
else:
|
|
324
|
+
click.secho(f"Found {result['count']} examples:", fg="cyan")
|
|
325
|
+
for ex in result["examples"]:
|
|
326
|
+
click.echo()
|
|
327
|
+
click.secho(f"--- {ex['file']}:{ex['line']} ---", fg="yellow")
|
|
328
|
+
click.echo(ex["context"])
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
# Advanced introspection commands
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
@introspect.command("hierarchy")
|
|
335
|
+
@click.argument("dotted_path")
|
|
336
|
+
@click.option("--builtins", is_flag=True, help="Include builtin classes")
|
|
337
|
+
@click.option("--max-depth", "-d", type=int, default=10, help="Max subclass depth")
|
|
338
|
+
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
339
|
+
def class_hierarchy(dotted_path, builtins, max_depth, as_json):
|
|
340
|
+
"""Get class inheritance hierarchy (MRO + subclasses)"""
|
|
341
|
+
from scitex.introspect import get_class_hierarchy
|
|
342
|
+
|
|
343
|
+
result = get_class_hierarchy(
|
|
344
|
+
dotted_path, include_builtins=builtins, max_depth=max_depth
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
if not result.get("success", False):
|
|
348
|
+
click.secho(f"Error: {result.get('error', 'Unknown error')}", fg="red")
|
|
349
|
+
sys.exit(1)
|
|
350
|
+
|
|
351
|
+
if as_json:
|
|
352
|
+
click.echo(json.dumps(result, indent=2))
|
|
353
|
+
else:
|
|
354
|
+
click.secho(f"Class: {dotted_path}", fg="cyan", bold=True)
|
|
355
|
+
click.secho(f"\nMRO ({result['mro_count']} classes):", fg="yellow")
|
|
356
|
+
for cls in result["mro"]:
|
|
357
|
+
click.echo(f" {cls['qualname']}")
|
|
358
|
+
click.secho(f"\nSubclasses ({result['subclass_count']}):", fg="yellow")
|
|
359
|
+
_print_subclasses(result.get("subclasses", []), indent=2)
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def _print_subclasses(subclasses, indent=0):
|
|
363
|
+
"""Helper to print subclass tree."""
|
|
364
|
+
for sub in subclasses:
|
|
365
|
+
click.echo(" " * indent + f"- {sub['qualname']}")
|
|
366
|
+
if "subclasses" in sub:
|
|
367
|
+
_print_subclasses(sub["subclasses"], indent + 2)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
@introspect.command("hints")
|
|
371
|
+
@click.argument("dotted_path")
|
|
372
|
+
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
373
|
+
def type_hints(dotted_path, as_json):
|
|
374
|
+
"""Get detailed type hint analysis"""
|
|
375
|
+
from scitex.introspect import get_type_hints_detailed
|
|
376
|
+
|
|
377
|
+
result = get_type_hints_detailed(dotted_path)
|
|
378
|
+
|
|
379
|
+
if not result.get("success", False):
|
|
380
|
+
click.secho(f"Error: {result.get('error', 'Unknown error')}", fg="red")
|
|
381
|
+
sys.exit(1)
|
|
382
|
+
|
|
383
|
+
if as_json:
|
|
384
|
+
click.echo(json.dumps(result, indent=2))
|
|
385
|
+
else:
|
|
386
|
+
click.secho(f"Type hints ({result['hint_count']}):", fg="cyan")
|
|
387
|
+
for name, info in result.get("hints", {}).items():
|
|
388
|
+
opt = " (optional)" if info.get("is_optional") else ""
|
|
389
|
+
click.echo(f" {name}: {info['raw']}{opt}")
|
|
390
|
+
if result.get("return_hint"):
|
|
391
|
+
click.secho(f"\nReturn: {result['return_hint']['raw']}", fg="green")
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
@introspect.command("imports")
|
|
395
|
+
@click.argument("dotted_path")
|
|
396
|
+
@click.option("--no-categorize", is_flag=True, help="Don't group by category")
|
|
397
|
+
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
398
|
+
def imports(dotted_path, no_categorize, as_json):
|
|
399
|
+
"""Get all imports from a module (AST-based)"""
|
|
400
|
+
from scitex.introspect import get_imports
|
|
401
|
+
|
|
402
|
+
result = get_imports(dotted_path, categorize=not no_categorize)
|
|
403
|
+
|
|
404
|
+
if not result.get("success", False):
|
|
405
|
+
click.secho(f"Error: {result.get('error', 'Unknown error')}", fg="red")
|
|
406
|
+
sys.exit(1)
|
|
407
|
+
|
|
408
|
+
if as_json:
|
|
409
|
+
click.echo(json.dumps(result, indent=2))
|
|
410
|
+
else:
|
|
411
|
+
click.secho(f"Imports ({result['import_count']}):", fg="cyan")
|
|
412
|
+
if result.get("categories"):
|
|
413
|
+
for cat, imps in result["categories"].items():
|
|
414
|
+
if imps:
|
|
415
|
+
click.secho(f"\n [{cat}] ({len(imps)}):", fg="yellow")
|
|
416
|
+
for imp in imps:
|
|
417
|
+
click.echo(f" {imp['module']}")
|
|
418
|
+
else:
|
|
419
|
+
for imp in result["imports"]:
|
|
420
|
+
click.echo(f" {imp['module']}")
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
@introspect.command("deps")
|
|
424
|
+
@click.argument("dotted_path")
|
|
425
|
+
@click.option("--recursive", "-r", is_flag=True, help="Recursive analysis")
|
|
426
|
+
@click.option("--max-depth", "-d", type=int, default=3, help="Max recursion depth")
|
|
427
|
+
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
428
|
+
def dependencies(dotted_path, recursive, max_depth, as_json):
|
|
429
|
+
"""Get module dependencies"""
|
|
430
|
+
from scitex.introspect import get_dependencies
|
|
431
|
+
|
|
432
|
+
result = get_dependencies(dotted_path, recursive=recursive, max_depth=max_depth)
|
|
433
|
+
|
|
434
|
+
if not result.get("success", False):
|
|
435
|
+
click.secho(f"Error: {result.get('error', 'Unknown error')}", fg="red")
|
|
436
|
+
sys.exit(1)
|
|
437
|
+
|
|
438
|
+
if as_json:
|
|
439
|
+
click.echo(json.dumps(result, indent=2))
|
|
440
|
+
else:
|
|
441
|
+
click.secho(f"Dependencies ({result['dependency_count']}):", fg="cyan")
|
|
442
|
+
for dep in result.get("dependencies", []):
|
|
443
|
+
click.echo(f" {dep}")
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
@introspect.command("calls")
|
|
447
|
+
@click.argument("dotted_path")
|
|
448
|
+
@click.option("--timeout", "-t", type=int, default=10, help="Timeout in seconds")
|
|
449
|
+
@click.option("--all", "all_calls", is_flag=True, help="Include external calls")
|
|
450
|
+
@click.option("--json", "as_json", is_flag=True, help="Output as JSON")
|
|
451
|
+
def call_graph(dotted_path, timeout, all_calls, as_json):
|
|
452
|
+
"""Get function call graph (with timeout protection)"""
|
|
453
|
+
from scitex.introspect import get_call_graph
|
|
454
|
+
|
|
455
|
+
result = get_call_graph(
|
|
456
|
+
dotted_path, timeout_seconds=timeout, internal_only=not all_calls
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
if not result.get("success", False):
|
|
460
|
+
click.secho(f"Error: {result.get('error', 'Unknown error')}", fg="red")
|
|
461
|
+
sys.exit(1)
|
|
462
|
+
|
|
463
|
+
if as_json:
|
|
464
|
+
click.echo(json.dumps(result, indent=2))
|
|
465
|
+
else:
|
|
466
|
+
if "calls" in result:
|
|
467
|
+
click.secho(f"Calls ({result['call_count']}):", fg="cyan")
|
|
468
|
+
for call in result["calls"]:
|
|
469
|
+
click.echo(f" -> {call['name']} (line {call['line']})")
|
|
470
|
+
click.secho(f"\nCalled by ({result['caller_count']}):", fg="yellow")
|
|
471
|
+
for caller in result.get("called_by", []):
|
|
472
|
+
click.echo(f" <- {caller['name']} (line {caller['line']})")
|
|
473
|
+
elif "graph" in result:
|
|
474
|
+
click.secho(
|
|
475
|
+
f"Module call graph ({result['function_count']} functions):", fg="cyan"
|
|
476
|
+
)
|
|
477
|
+
for func, info in result["graph"].items():
|
|
478
|
+
calls = ", ".join(c["name"] for c in info["calls"][:5])
|
|
479
|
+
if len(info["calls"]) > 5:
|
|
480
|
+
calls += "..."
|
|
481
|
+
click.echo(f" {func}: {calls or '(no calls)'}")
|