scitex 2.16.0__py3-none-any.whl → 2.16.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/_mcp_tools/audio.py +11 -65
- scitex/audio/README.md +40 -12
- scitex/audio/__init__.py +27 -235
- scitex/audio/_audio_check.py +93 -0
- scitex/audio/_mcp/speak_handlers.py +56 -8
- scitex/audio/_speak.py +295 -0
- scitex/audio/mcp_server.py +98 -73
- 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/social/__init__.py +1 -24
- scitex/writer/README.md +25 -409
- scitex/writer/__init__.py +98 -13
- {scitex-2.16.0.dist-info → scitex-2.16.2.dist-info}/METADATA +6 -1
- {scitex-2.16.0.dist-info → scitex-2.16.2.dist-info}/RECORD +21 -93
- 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/writer/Writer.py +0 -487
- scitex/writer/_clone_writer_project.py +0 -160
- scitex/writer/_compile/__init__.py +0 -41
- scitex/writer/_compile/_compile_async.py +0 -130
- scitex/writer/_compile/_compile_unified.py +0 -148
- scitex/writer/_compile/_parser.py +0 -63
- scitex/writer/_compile/_runner.py +0 -457
- scitex/writer/_compile/_validator.py +0 -46
- scitex/writer/_compile/manuscript.py +0 -110
- scitex/writer/_compile/revision.py +0 -82
- scitex/writer/_compile/supplementary.py +0 -100
- scitex/writer/_dataclasses/__init__.py +0 -44
- scitex/writer/_dataclasses/config/_CONSTANTS.py +0 -46
- scitex/writer/_dataclasses/config/_WriterConfig.py +0 -175
- scitex/writer/_dataclasses/config/__init__.py +0 -9
- scitex/writer/_dataclasses/contents/_ManuscriptContents.py +0 -236
- scitex/writer/_dataclasses/contents/_RevisionContents.py +0 -136
- scitex/writer/_dataclasses/contents/_SupplementaryContents.py +0 -114
- scitex/writer/_dataclasses/contents/__init__.py +0 -9
- scitex/writer/_dataclasses/core/_Document.py +0 -146
- scitex/writer/_dataclasses/core/_DocumentSection.py +0 -546
- scitex/writer/_dataclasses/core/__init__.py +0 -7
- scitex/writer/_dataclasses/results/_CompilationResult.py +0 -165
- scitex/writer/_dataclasses/results/_LaTeXIssue.py +0 -102
- scitex/writer/_dataclasses/results/_SaveSectionsResponse.py +0 -118
- scitex/writer/_dataclasses/results/_SectionReadResponse.py +0 -131
- scitex/writer/_dataclasses/results/__init__.py +0 -11
- scitex/writer/_dataclasses/tree/MINIMUM_FILES.md +0 -121
- scitex/writer/_dataclasses/tree/_ConfigTree.py +0 -86
- scitex/writer/_dataclasses/tree/_ManuscriptTree.py +0 -84
- scitex/writer/_dataclasses/tree/_RevisionTree.py +0 -97
- scitex/writer/_dataclasses/tree/_ScriptsTree.py +0 -118
- scitex/writer/_dataclasses/tree/_SharedTree.py +0 -100
- scitex/writer/_dataclasses/tree/_SupplementaryTree.py +0 -101
- scitex/writer/_dataclasses/tree/__init__.py +0 -23
- scitex/writer/_mcp/__init__.py +0 -4
- scitex/writer/_mcp/handlers.py +0 -32
- scitex/writer/_mcp/tool_schemas.py +0 -33
- scitex/writer/_project/__init__.py +0 -29
- scitex/writer/_project/_create.py +0 -89
- scitex/writer/_project/_trees.py +0 -63
- scitex/writer/_project/_validate.py +0 -61
- scitex/writer/utils/.legacy_git_retry.py +0 -164
- scitex/writer/utils/__init__.py +0 -24
- scitex/writer/utils/_converters.py +0 -635
- scitex/writer/utils/_parse_latex_logs.py +0 -138
- scitex/writer/utils/_parse_script_args.py +0 -156
- scitex/writer/utils/_verify_tree_structure.py +0 -205
- scitex/writer/utils/_watch.py +0 -96
- {scitex-2.16.0.dist-info → scitex-2.16.2.dist-info}/WHEEL +0 -0
- {scitex-2.16.0.dist-info → scitex-2.16.2.dist-info}/entry_points.txt +0 -0
- {scitex-2.16.0.dist-info → scitex-2.16.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
# Timestamp: "2025-10-28 17:11:22 (ywatanabe)"
|
|
4
|
-
# File: /home/ywatanabe/proj/scitex-code/src/scitex/writer/parse_latex.py
|
|
5
|
-
# ----------------------------------------
|
|
6
|
-
from __future__ import annotations
|
|
7
|
-
import os
|
|
8
|
-
|
|
9
|
-
__FILE__ = "./src/scitex/writer/parse_latex.py"
|
|
10
|
-
__DIR__ = os.path.dirname(__FILE__)
|
|
11
|
-
# ----------------------------------------
|
|
12
|
-
|
|
13
|
-
"""
|
|
14
|
-
LaTeX error and warning parsing from compilation output.
|
|
15
|
-
|
|
16
|
-
Simple parsing of LaTeX errors and warnings from stdout/stderr.
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
from pathlib import Path
|
|
20
|
-
from typing import List
|
|
21
|
-
from typing import Tuple
|
|
22
|
-
|
|
23
|
-
from .._dataclasses import LaTeXIssue
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def parse_compilation_output(
|
|
27
|
-
output: str, log_file: Path = None
|
|
28
|
-
) -> Tuple[List[LaTeXIssue], List[LaTeXIssue]]:
|
|
29
|
-
"""
|
|
30
|
-
Parse errors and warnings from compilation output.
|
|
31
|
-
|
|
32
|
-
Args:
|
|
33
|
-
output: Compilation output (stdout + stderr)
|
|
34
|
-
log_file: Optional path to .log file (unused, for compatibility)
|
|
35
|
-
|
|
36
|
-
Returns:
|
|
37
|
-
Tuple of (error_issues, warning_issues)
|
|
38
|
-
"""
|
|
39
|
-
errors = []
|
|
40
|
-
warnings = []
|
|
41
|
-
|
|
42
|
-
for line in output.split("\n"):
|
|
43
|
-
# LaTeX error pattern: "! Error message"
|
|
44
|
-
if line.startswith("!"):
|
|
45
|
-
error_text = line[1:].strip()
|
|
46
|
-
if error_text:
|
|
47
|
-
errors.append(LaTeXIssue(type="error", message=error_text))
|
|
48
|
-
|
|
49
|
-
# LaTeX warning pattern
|
|
50
|
-
elif "warning" in line.lower():
|
|
51
|
-
warnings.append(LaTeXIssue(type="warning", message=line.strip()))
|
|
52
|
-
|
|
53
|
-
return errors, warnings
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def run_session() -> None:
|
|
57
|
-
"""Initialize scitex framework, run main function, and cleanup."""
|
|
58
|
-
global CONFIG, CC, sys, plt, rng
|
|
59
|
-
import sys
|
|
60
|
-
import matplotlib.pyplot as plt
|
|
61
|
-
import scitex as stx
|
|
62
|
-
|
|
63
|
-
args = parse_args()
|
|
64
|
-
|
|
65
|
-
CONFIG, sys.stdout, sys.stderr, plt, CC, rng = stx.session.start(
|
|
66
|
-
sys,
|
|
67
|
-
plt,
|
|
68
|
-
args=args,
|
|
69
|
-
file=__FILE__,
|
|
70
|
-
sdir_suffix=None,
|
|
71
|
-
verbose=False,
|
|
72
|
-
agg=True,
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
exit_status = main(args)
|
|
76
|
-
|
|
77
|
-
stx.session.close(
|
|
78
|
-
CONFIG,
|
|
79
|
-
verbose=False,
|
|
80
|
-
notify=False,
|
|
81
|
-
message="",
|
|
82
|
-
exit_status=exit_status,
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def main(args):
|
|
87
|
-
if args.file:
|
|
88
|
-
with open(args.file) as f_f:
|
|
89
|
-
output = f_f.read()
|
|
90
|
-
else:
|
|
91
|
-
output = args.text
|
|
92
|
-
|
|
93
|
-
errors, warnings = parse_compilation_output(output)
|
|
94
|
-
|
|
95
|
-
print(f"Errors: {len(errors)}")
|
|
96
|
-
for err in errors:
|
|
97
|
-
print(f" - {err}")
|
|
98
|
-
|
|
99
|
-
print(f"Warnings: {len(warnings)}")
|
|
100
|
-
for warn in warnings:
|
|
101
|
-
print(f" - {warn}")
|
|
102
|
-
|
|
103
|
-
return 0
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
def parse_args():
|
|
107
|
-
import argparse
|
|
108
|
-
|
|
109
|
-
parser = argparse.ArgumentParser(
|
|
110
|
-
description="Parse LaTeX compilation output for errors and warnings"
|
|
111
|
-
)
|
|
112
|
-
parser.add_argument(
|
|
113
|
-
"--file",
|
|
114
|
-
"-f",
|
|
115
|
-
type=str,
|
|
116
|
-
help="File containing compilation output",
|
|
117
|
-
)
|
|
118
|
-
parser.add_argument(
|
|
119
|
-
"--text",
|
|
120
|
-
"-t",
|
|
121
|
-
type=str,
|
|
122
|
-
help="Compilation output text",
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
return parser.parse_args()
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if __name__ == "__main__":
|
|
129
|
-
run_session()
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
__all__ = [
|
|
133
|
-
"parse_compilation_output",
|
|
134
|
-
]
|
|
135
|
-
|
|
136
|
-
# python -m scitex.writer.utils._parse_latex_logs --file compilation.log
|
|
137
|
-
|
|
138
|
-
# EOF
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
# Timestamp: "2025-10-28 17:30:00 (ywatanabe)"
|
|
4
|
-
# File: /home/ywatanabe/proj/scitex-code/src/scitex/writer/_parse_script_args.py
|
|
5
|
-
# ----------------------------------------
|
|
6
|
-
from __future__ import annotations
|
|
7
|
-
import os
|
|
8
|
-
|
|
9
|
-
__FILE__ = "./src/scitex/writer/_parse_script_args.py"
|
|
10
|
-
__DIR__ = os.path.dirname(__FILE__)
|
|
11
|
-
# ----------------------------------------
|
|
12
|
-
|
|
13
|
-
"""
|
|
14
|
-
Script argument parser - extract available arguments from shell scripts.
|
|
15
|
-
|
|
16
|
-
Parses shell scripts to extract documented arguments from usage() functions.
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
import re
|
|
20
|
-
from pathlib import Path
|
|
21
|
-
from dataclasses import dataclass
|
|
22
|
-
from typing import Optional
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
@dataclass
|
|
26
|
-
class ScriptArgument:
|
|
27
|
-
"""Represents a single script argument."""
|
|
28
|
-
|
|
29
|
-
short_flag: Optional[str] # e.g., "-nf"
|
|
30
|
-
long_flag: Optional[str] # e.g., "--no_figs"
|
|
31
|
-
description: str # e.g., "Exclude figures for quick compilation"
|
|
32
|
-
default: Optional[str] # e.g., "false"
|
|
33
|
-
|
|
34
|
-
def __str__(self) -> str:
|
|
35
|
-
"""Format as help text."""
|
|
36
|
-
flags = ", ".join(f for f in [self.short_flag, self.long_flag] if f)
|
|
37
|
-
default_str = f" (default: {self.default})" if self.default else ""
|
|
38
|
-
return f"{flags:20} {self.description}{default_str}"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
class ScriptArgumentParser:
|
|
42
|
-
"""Extract arguments from shell script usage() functions."""
|
|
43
|
-
|
|
44
|
-
@staticmethod
|
|
45
|
-
def parse(script_path: Path) -> list[ScriptArgument]:
|
|
46
|
-
"""
|
|
47
|
-
Parse shell script to extract available arguments.
|
|
48
|
-
|
|
49
|
-
Looks for usage() function pattern:
|
|
50
|
-
-flag, --long-flag Description (default: value)
|
|
51
|
-
|
|
52
|
-
Args:
|
|
53
|
-
script_path: Path to shell script
|
|
54
|
-
|
|
55
|
-
Returns:
|
|
56
|
-
List of ScriptArgument objects
|
|
57
|
-
"""
|
|
58
|
-
if not script_path.exists():
|
|
59
|
-
return []
|
|
60
|
-
|
|
61
|
-
content = script_path.read_text()
|
|
62
|
-
|
|
63
|
-
# Find usage() function
|
|
64
|
-
usage_match = re.search(r"usage\s*\(\)\s*{(.*?)exit\s+0", content, re.DOTALL)
|
|
65
|
-
|
|
66
|
-
if not usage_match:
|
|
67
|
-
return []
|
|
68
|
-
|
|
69
|
-
usage_text = usage_match.group(1)
|
|
70
|
-
|
|
71
|
-
# Extract arguments from usage text (contains echo statements)
|
|
72
|
-
# Find all lines with option flags (start with "echo" and contain flags)
|
|
73
|
-
options_text = usage_text
|
|
74
|
-
args = []
|
|
75
|
-
|
|
76
|
-
# Parse each line in usage (will contain echo statements)
|
|
77
|
-
for line in options_text.split("\n"):
|
|
78
|
-
# Extract content between quotes in echo statements
|
|
79
|
-
quote_match = re.search(r'"([^"]*)"', line)
|
|
80
|
-
if not quote_match:
|
|
81
|
-
continue
|
|
82
|
-
|
|
83
|
-
line_content = quote_match.group(1).strip()
|
|
84
|
-
if not line_content or line_content.startswith("#"):
|
|
85
|
-
continue
|
|
86
|
-
|
|
87
|
-
# Skip lines without flags
|
|
88
|
-
if "-" not in line_content:
|
|
89
|
-
continue
|
|
90
|
-
|
|
91
|
-
arg = ScriptArgumentParser._parse_argument_line(line_content)
|
|
92
|
-
if arg:
|
|
93
|
-
args.append(arg)
|
|
94
|
-
|
|
95
|
-
return args
|
|
96
|
-
|
|
97
|
-
@staticmethod
|
|
98
|
-
def _parse_argument_line(line: str) -> Optional[ScriptArgument]:
|
|
99
|
-
"""
|
|
100
|
-
Parse single argument line.
|
|
101
|
-
|
|
102
|
-
Format: "-nf, --no_figs Description (default: value)"
|
|
103
|
-
"""
|
|
104
|
-
# Extract flags and description
|
|
105
|
-
flags_match = re.match(r"(.*?)\s{2,}(.*)", line)
|
|
106
|
-
if not flags_match:
|
|
107
|
-
return None
|
|
108
|
-
|
|
109
|
-
flags_str = flags_match.group(1).strip()
|
|
110
|
-
rest = flags_match.group(2).strip()
|
|
111
|
-
|
|
112
|
-
# Parse flags
|
|
113
|
-
short_flag = None
|
|
114
|
-
long_flag = None
|
|
115
|
-
|
|
116
|
-
if "," in flags_str:
|
|
117
|
-
parts = flags_str.split(",")
|
|
118
|
-
short_flag = parts[0].strip() if parts[0].strip() else None
|
|
119
|
-
long_flag = (
|
|
120
|
-
parts[1].strip() if len(parts) > 1 and parts[1].strip() else None
|
|
121
|
-
)
|
|
122
|
-
else:
|
|
123
|
-
# Single flag (short or long)
|
|
124
|
-
if flags_str.startswith("--"):
|
|
125
|
-
long_flag = flags_str
|
|
126
|
-
elif flags_str.startswith("-"):
|
|
127
|
-
short_flag = flags_str
|
|
128
|
-
else:
|
|
129
|
-
return None
|
|
130
|
-
|
|
131
|
-
# Parse description and default
|
|
132
|
-
description = rest
|
|
133
|
-
default = None
|
|
134
|
-
|
|
135
|
-
default_match = re.search(r"\(default:\s*([^)]+)\)", rest)
|
|
136
|
-
if default_match:
|
|
137
|
-
default = default_match.group(1).strip()
|
|
138
|
-
description = rest[: default_match.start()].strip()
|
|
139
|
-
|
|
140
|
-
if not description:
|
|
141
|
-
return None
|
|
142
|
-
|
|
143
|
-
return ScriptArgument(
|
|
144
|
-
short_flag=short_flag,
|
|
145
|
-
long_flag=long_flag,
|
|
146
|
-
description=description,
|
|
147
|
-
default=default,
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
__all__ = [
|
|
152
|
-
"ScriptArgument",
|
|
153
|
-
"ScriptArgumentParser",
|
|
154
|
-
]
|
|
155
|
-
|
|
156
|
-
# EOF
|
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# Timestamp: "2025-10-29 06:13:05 (ywatanabe)"
|
|
3
|
-
# File: /home/ywatanabe/proj/scitex-code/src/scitex/writer/_verify_tree_structure.py
|
|
4
|
-
# ----------------------------------------
|
|
5
|
-
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
import os
|
|
8
|
-
|
|
9
|
-
__FILE__ = "./src/scitex/writer/_verify_tree_structure.py"
|
|
10
|
-
__DIR__ = os.path.dirname(__FILE__)
|
|
11
|
-
# ----------------------------------------
|
|
12
|
-
|
|
13
|
-
import argparse
|
|
14
|
-
|
|
15
|
-
"""Project structure validation for writer module.
|
|
16
|
-
|
|
17
|
-
Leverages dataclass verify_structure() methods for validation."""
|
|
18
|
-
|
|
19
|
-
from pathlib import Path
|
|
20
|
-
|
|
21
|
-
from scitex.logging import getLogger
|
|
22
|
-
|
|
23
|
-
from .._dataclasses import (
|
|
24
|
-
ConfigTree,
|
|
25
|
-
ManuscriptTree,
|
|
26
|
-
RevisionTree,
|
|
27
|
-
ScriptsTree,
|
|
28
|
-
SharedTree,
|
|
29
|
-
SupplementaryTree,
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
logger = getLogger(__name__)
|
|
33
|
-
|
|
34
|
-
# Parameters
|
|
35
|
-
TREE_VALIDATORS = {
|
|
36
|
-
"config": {"dir_name": "config", "tree_class": ConfigTree},
|
|
37
|
-
"00_shared": {"dir_name": "00_shared", "tree_class": SharedTree},
|
|
38
|
-
"01_manuscript": {
|
|
39
|
-
"dir_name": "01_manuscript",
|
|
40
|
-
"tree_class": ManuscriptTree,
|
|
41
|
-
},
|
|
42
|
-
"02_supplementary": {
|
|
43
|
-
"dir_name": "02_supplementary",
|
|
44
|
-
"tree_class": SupplementaryTree,
|
|
45
|
-
},
|
|
46
|
-
"03_revision": {"dir_name": "03_revision", "tree_class": RevisionTree},
|
|
47
|
-
"scripts": {"dir_name": "scripts", "tree_class": ScriptsTree},
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
# Exception classes
|
|
52
|
-
class ProjectValidationError(Exception):
|
|
53
|
-
"""Raised when project structure is invalid."""
|
|
54
|
-
|
|
55
|
-
pass
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
# 2. Public validation functions
|
|
59
|
-
def verify_tree_structure(
|
|
60
|
-
project_dir: Path, func_name="validate_tree_structures"
|
|
61
|
-
) -> None:
|
|
62
|
-
"""Validates all tree structures in the project directory."""
|
|
63
|
-
logger.info(
|
|
64
|
-
f"{func_name}: Validating tree structures: {Path(project_dir).absolute()}..."
|
|
65
|
-
)
|
|
66
|
-
project_dir = Path(project_dir)
|
|
67
|
-
for dir_name, (dir_path, tree_class) in TREE_VALIDATORS.items():
|
|
68
|
-
validator_func_name = f"_validate_{dir_name}_structure"
|
|
69
|
-
eval(validator_func_name)(project_dir)
|
|
70
|
-
logger.success(
|
|
71
|
-
f"{func_name}: Validated tree structures: {Path(project_dir).absolute()}"
|
|
72
|
-
)
|
|
73
|
-
return True
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
# 3. Internal validation functions
|
|
77
|
-
def _validate_01_manuscript_structure(project_dir: Path) -> bool:
|
|
78
|
-
"""Validates manuscript structure."""
|
|
79
|
-
return _validate_tree_structure_base(
|
|
80
|
-
project_dir, **TREE_VALIDATORS["01_manuscript"]
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def _validate_02_supplementary_structure(project_dir: Path) -> bool:
|
|
85
|
-
"""Validates supplementary structure."""
|
|
86
|
-
return _validate_tree_structure_base(
|
|
87
|
-
project_dir, **TREE_VALIDATORS["02_supplementary"]
|
|
88
|
-
)
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def _validate_03_revision_structure(project_dir: Path) -> bool:
|
|
92
|
-
"""Validates revision structure."""
|
|
93
|
-
return _validate_tree_structure_base(project_dir, **TREE_VALIDATORS["03_revision"])
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
def _validate_config_structure(project_dir: Path) -> bool:
|
|
97
|
-
"""Validates config structure."""
|
|
98
|
-
return _validate_tree_structure_base(project_dir, **TREE_VALIDATORS["config"])
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def _validate_scripts_structure(project_dir: Path) -> bool:
|
|
102
|
-
"""Validates scripts structure."""
|
|
103
|
-
return _validate_tree_structure_base(project_dir, **TREE_VALIDATORS["scripts"])
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
def _validate_00_shared_structure(project_dir: Path) -> bool:
|
|
107
|
-
"""Validates shared structure."""
|
|
108
|
-
return _validate_tree_structure_base(project_dir, **TREE_VALIDATORS["00_shared"])
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
# 4. Helper functions
|
|
112
|
-
def _validate_tree_structure_base(
|
|
113
|
-
project_dir: Path, dir_name: str, tree_class: type = None
|
|
114
|
-
) -> bool:
|
|
115
|
-
"""Base validation function that checks directory existence and verifies structure using tree class.
|
|
116
|
-
|
|
117
|
-
Args:
|
|
118
|
-
project_dir: Root project directory
|
|
119
|
-
dir_name: Name of directory to validate
|
|
120
|
-
tree_class: Tree class with verify_structure method
|
|
121
|
-
|
|
122
|
-
Returns
|
|
123
|
-
-------
|
|
124
|
-
True if structure is valid
|
|
125
|
-
|
|
126
|
-
Raises
|
|
127
|
-
------
|
|
128
|
-
ProjectValidationError: If directory missing or structure invalid
|
|
129
|
-
"""
|
|
130
|
-
project_dir = Path(project_dir)
|
|
131
|
-
target_dir = project_dir / dir_name
|
|
132
|
-
if not target_dir.exists():
|
|
133
|
-
raise ProjectValidationError(f"Required directory missing: {target_dir}")
|
|
134
|
-
if tree_class is not None:
|
|
135
|
-
doc = tree_class(target_dir, git_root=project_dir)
|
|
136
|
-
is_valid, issues = doc.verify_structure()
|
|
137
|
-
if not is_valid:
|
|
138
|
-
raise ProjectValidationError(
|
|
139
|
-
f"{dir_name} structure invalid:\n"
|
|
140
|
-
+ "\n".join(f" - {issue}" for issue in issues)
|
|
141
|
-
)
|
|
142
|
-
logger.debug(f"{dir_name} structure valid: {project_dir}")
|
|
143
|
-
return True
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
# 1. Main entry point
|
|
147
|
-
def run_session() -> None:
|
|
148
|
-
"""Initialize scitex framework, run main function, and cleanup."""
|
|
149
|
-
global CONFIG, CC, sys, plt, rng
|
|
150
|
-
import sys
|
|
151
|
-
|
|
152
|
-
import matplotlib.pyplot as plt
|
|
153
|
-
|
|
154
|
-
import scitex as stx
|
|
155
|
-
|
|
156
|
-
args = parse_args()
|
|
157
|
-
|
|
158
|
-
CONFIG, sys.stdout, sys.stderr, plt, CC, rng = stx.session.start(
|
|
159
|
-
sys,
|
|
160
|
-
plt,
|
|
161
|
-
args=args,
|
|
162
|
-
file=__FILE__,
|
|
163
|
-
sdir_suffix=None,
|
|
164
|
-
verbose=False,
|
|
165
|
-
agg=True,
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
exit_status = main(args)
|
|
169
|
-
|
|
170
|
-
stx.session.close(
|
|
171
|
-
CONFIG,
|
|
172
|
-
verbose=False,
|
|
173
|
-
notify=False,
|
|
174
|
-
message="",
|
|
175
|
-
exit_status=exit_status,
|
|
176
|
-
)
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
def main(args):
|
|
180
|
-
project_dir = Path(args.dir) if args.dir else Path.cwd()
|
|
181
|
-
verify_tree_structure(project_dir)
|
|
182
|
-
return 0
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
def parse_args() -> argparse.Namespace:
|
|
186
|
-
parser = argparse.ArgumentParser(
|
|
187
|
-
description="Validate scitex writer project structure"
|
|
188
|
-
)
|
|
189
|
-
parser.add_argument(
|
|
190
|
-
"--dir",
|
|
191
|
-
"-d",
|
|
192
|
-
type=str,
|
|
193
|
-
default=None,
|
|
194
|
-
help="Project directory to validate (default: current directory)",
|
|
195
|
-
)
|
|
196
|
-
args = parser.parse_args()
|
|
197
|
-
return args
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
if __name__ == "__main__":
|
|
201
|
-
run_session()
|
|
202
|
-
|
|
203
|
-
# python -m scitex.writer._verify_tree_structure --dir ./my_paper
|
|
204
|
-
|
|
205
|
-
# EOF
|
scitex/writer/utils/_watch.py
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
# File: /home/ywatanabe/proj/scitex-code/src/scitex/writer/watch.py
|
|
4
|
-
|
|
5
|
-
"""
|
|
6
|
-
Watch mode for auto-recompilation.
|
|
7
|
-
|
|
8
|
-
Monitors file changes and triggers automatic recompilation.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
import subprocess
|
|
12
|
-
from pathlib import Path
|
|
13
|
-
from typing import Optional, Callable
|
|
14
|
-
|
|
15
|
-
from scitex.logging import getLogger
|
|
16
|
-
|
|
17
|
-
logger = getLogger(__name__)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def watch_manuscript(
|
|
21
|
-
project_dir: Path,
|
|
22
|
-
interval: int = 2,
|
|
23
|
-
on_compile: Optional[Callable] = None,
|
|
24
|
-
timeout: Optional[int] = None,
|
|
25
|
-
) -> None:
|
|
26
|
-
"""
|
|
27
|
-
Watch and auto-recompile manuscript on file changes.
|
|
28
|
-
|
|
29
|
-
Args:
|
|
30
|
-
project_dir: Path to writer project directory
|
|
31
|
-
interval: Check interval in seconds
|
|
32
|
-
on_compile: Callback function called after each compilation
|
|
33
|
-
timeout: Optional timeout in seconds (None = infinite)
|
|
34
|
-
|
|
35
|
-
Examples:
|
|
36
|
-
>>> from pathlib import Path
|
|
37
|
-
>>> def on_change():
|
|
38
|
-
... print("Recompiled!")
|
|
39
|
-
>>> watch_manuscript(Path("/path/to/project"), on_compile=on_change)
|
|
40
|
-
"""
|
|
41
|
-
# Get compile script from project directory
|
|
42
|
-
compile_script = project_dir / "compile"
|
|
43
|
-
|
|
44
|
-
if not compile_script.exists():
|
|
45
|
-
logger.error(f"compile script not found: {compile_script}")
|
|
46
|
-
return
|
|
47
|
-
|
|
48
|
-
# Build watch command
|
|
49
|
-
cmd = [str(compile_script), "-m", "-w"]
|
|
50
|
-
|
|
51
|
-
logger.info(f"Starting watch mode for {project_dir}")
|
|
52
|
-
logger.info("Press Ctrl+C to stop")
|
|
53
|
-
|
|
54
|
-
try:
|
|
55
|
-
# Run watch script
|
|
56
|
-
process = subprocess.Popen(
|
|
57
|
-
cmd,
|
|
58
|
-
cwd=project_dir,
|
|
59
|
-
stdout=subprocess.PIPE,
|
|
60
|
-
stderr=subprocess.STDOUT,
|
|
61
|
-
text=True,
|
|
62
|
-
bufsize=1, # Line-buffered
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
# Stream output
|
|
66
|
-
for line in iter(process.stdout.readline, ""):
|
|
67
|
-
if line:
|
|
68
|
-
print(line.rstrip())
|
|
69
|
-
|
|
70
|
-
# Call callback on compilation events
|
|
71
|
-
if on_compile and "Compilation" in line:
|
|
72
|
-
try:
|
|
73
|
-
on_compile()
|
|
74
|
-
except Exception as e:
|
|
75
|
-
logger.error(f"Callback error: {e}")
|
|
76
|
-
|
|
77
|
-
process.wait(timeout=timeout)
|
|
78
|
-
|
|
79
|
-
except KeyboardInterrupt:
|
|
80
|
-
logger.info("\nWatch mode stopped by user")
|
|
81
|
-
if process:
|
|
82
|
-
process.terminate()
|
|
83
|
-
try:
|
|
84
|
-
process.wait(timeout=5)
|
|
85
|
-
except subprocess.TimeoutExpired:
|
|
86
|
-
process.kill()
|
|
87
|
-
|
|
88
|
-
except Exception as e:
|
|
89
|
-
logger.error(f"Watch mode error: {e}")
|
|
90
|
-
if process:
|
|
91
|
-
process.terminate()
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
__all__ = ["watch_manuscript"]
|
|
95
|
-
|
|
96
|
-
# EOF
|
|
File without changes
|
|
File without changes
|
|
File without changes
|