@heylemon/lemonade 0.0.4 → 0.0.6
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.
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/gateway/skills-http.js +74 -19
- package/package.json +1 -1
- package/skills/docx/SKILL.md +25 -30
- package/skills/docx/scripts/accept_changes.py +0 -17
- package/skills/docx/scripts/comment.py +10 -39
- package/skills/docx/scripts/office/helpers/merge_runs.py +1 -33
- package/skills/docx/scripts/office/helpers/simplify_redlines.py +0 -43
- package/skills/docx/scripts/office/pack.py +0 -30
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -1499
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -1085
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -3081
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -287
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -1676
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -174
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -582
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -4439
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -570
- package/skills/docx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -116
- package/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -42
- package/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -50
- package/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -49
- package/skills/docx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -33
- package/skills/docx/scripts/office/soffice.py +0 -55
- package/skills/docx/scripts/office/unpack.py +5 -27
- package/skills/docx/scripts/office/validate.py +19 -14
- package/skills/docx/scripts/office/validators/base.py +48 -224
- package/skills/docx/scripts/office/validators/docx.py +44 -117
- package/skills/docx/scripts/office/validators/pptx.py +2 -42
- package/skills/docx/scripts/office/validators/redlining.py +3 -40
- package/skills/pdf/SKILL.md +22 -15
- package/skills/pdf/{FORMS.md → forms.md} +0 -14
- package/skills/pdf/scripts/check_bounding_boxes.py +0 -5
- package/skills/pdf/scripts/check_fillable_fields.py +0 -1
- package/skills/pdf/scripts/convert_pdf_to_images.py +0 -2
- package/skills/pdf/scripts/create_validation_image.py +0 -4
- package/skills/pdf/scripts/extract_form_field_info.py +1 -31
- package/skills/pdf/scripts/extract_form_structure.py +0 -9
- package/skills/pdf/scripts/fill_fillable_fields.py +0 -23
- package/skills/pdf/scripts/fill_pdf_form_with_annotations.py +3 -38
- package/skills/pptx/SKILL.md +2 -29
- package/skills/pptx/editing.md +2 -2
- package/skills/pptx/pptxgenjs.md +53 -8
- package/skills/pptx/scripts/add_slide.py +0 -30
- package/skills/pptx/scripts/clean.py +0 -23
- package/skills/pptx/scripts/office/helpers/merge_runs.py +1 -33
- package/skills/pptx/scripts/office/helpers/simplify_redlines.py +0 -43
- package/skills/pptx/scripts/office/pack.py +0 -30
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -1499
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -1085
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -3081
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -287
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -1676
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -174
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -582
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -4439
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -570
- package/skills/pptx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -116
- package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -42
- package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -50
- package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -49
- package/skills/pptx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -33
- package/skills/pptx/scripts/office/soffice.py +0 -55
- package/skills/pptx/scripts/office/unpack.py +5 -27
- package/skills/pptx/scripts/office/validate.py +19 -14
- package/skills/pptx/scripts/office/validators/base.py +48 -224
- package/skills/pptx/scripts/office/validators/docx.py +44 -117
- package/skills/pptx/scripts/office/validators/pptx.py +2 -42
- package/skills/pptx/scripts/office/validators/redlining.py +3 -40
- package/skills/pptx/scripts/thumbnail.py +0 -31
- package/skills/xlsx/SKILL.md +3 -26
- package/skills/xlsx/scripts/office/helpers/merge_runs.py +1 -33
- package/skills/xlsx/scripts/office/helpers/simplify_redlines.py +0 -43
- package/skills/xlsx/scripts/office/pack.py +0 -30
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -1499
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -1085
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -3081
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -287
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -1676
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -174
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -582
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -4439
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -570
- package/skills/xlsx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -116
- package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -42
- package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -50
- package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -49
- package/skills/xlsx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -33
- package/skills/xlsx/scripts/office/soffice.py +0 -55
- package/skills/xlsx/scripts/office/unpack.py +5 -27
- package/skills/xlsx/scripts/office/validate.py +19 -14
- package/skills/xlsx/scripts/office/validators/base.py +48 -224
- package/skills/xlsx/scripts/office/validators/docx.py +44 -117
- package/skills/xlsx/scripts/office/validators/pptx.py +2 -42
- package/skills/xlsx/scripts/office/validators/redlining.py +3 -40
- package/skills/xlsx/scripts/recalc.py +2 -26
- package/skills/docx/scripts/__init__.py +0 -1
- package/skills/docx/scripts/office/helpers/__init__.py +0 -0
- package/skills/docx/scripts/office/validators/__init__.py +0 -15
- package/skills/pptx/scripts/__init__.py +0 -0
- package/skills/pptx/scripts/office/helpers/__init__.py +0 -0
- package/skills/pptx/scripts/office/validators/__init__.py +0 -15
- package/skills/xlsx/scripts/office/helpers/__init__.py +0 -0
- package/skills/xlsx/scripts/office/validators/__init__.py +0 -15
- /package/skills/pdf/{REFERENCE.md → reference.md} +0 -0
|
@@ -9,7 +9,6 @@ from pathlib import Path
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class RedliningValidator:
|
|
12
|
-
"""Validator for tracked changes in Word documents."""
|
|
13
12
|
|
|
14
13
|
def __init__(self, unpacked_dir, original_docx, verbose=False, author="Claude"):
|
|
15
14
|
self.unpacked_dir = Path(unpacked_dir)
|
|
@@ -21,29 +20,23 @@ class RedliningValidator:
|
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
def repair(self) -> int:
|
|
24
|
-
"""No auto-repairs for redlining validation. Returns 0."""
|
|
25
23
|
return 0
|
|
26
24
|
|
|
27
25
|
def validate(self):
|
|
28
|
-
"""Main validation method that returns True if valid, False otherwise."""
|
|
29
|
-
# Verify unpacked directory exists and has correct structure
|
|
30
26
|
modified_file = self.unpacked_dir / "word" / "document.xml"
|
|
31
27
|
if not modified_file.exists():
|
|
32
28
|
print(f"FAILED - Modified document.xml not found at {modified_file}")
|
|
33
29
|
return False
|
|
34
30
|
|
|
35
|
-
# First, check if there are any tracked changes by the author to validate
|
|
36
31
|
try:
|
|
37
32
|
import xml.etree.ElementTree as ET
|
|
38
33
|
|
|
39
34
|
tree = ET.parse(modified_file)
|
|
40
35
|
root = tree.getroot()
|
|
41
36
|
|
|
42
|
-
# Check for w:del or w:ins tags by the specified author
|
|
43
37
|
del_elements = root.findall(".//w:del", self.namespaces)
|
|
44
38
|
ins_elements = root.findall(".//w:ins", self.namespaces)
|
|
45
39
|
|
|
46
|
-
# Filter to only include changes by the specified author
|
|
47
40
|
author_del_elements = [
|
|
48
41
|
elem
|
|
49
42
|
for elem in del_elements
|
|
@@ -55,21 +48,17 @@ class RedliningValidator:
|
|
|
55
48
|
if elem.get(f"{{{self.namespaces['w']}}}author") == self.author
|
|
56
49
|
]
|
|
57
50
|
|
|
58
|
-
# Redlining validation is only needed if tracked changes by the author have been used.
|
|
59
51
|
if not author_del_elements and not author_ins_elements:
|
|
60
52
|
if self.verbose:
|
|
61
53
|
print(f"PASSED - No tracked changes by {self.author} found.")
|
|
62
54
|
return True
|
|
63
55
|
|
|
64
56
|
except Exception:
|
|
65
|
-
# If we can't parse the XML, continue with full validation
|
|
66
57
|
pass
|
|
67
58
|
|
|
68
|
-
# Create temporary directory for unpacking original docx
|
|
69
59
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
70
60
|
temp_path = Path(temp_dir)
|
|
71
61
|
|
|
72
|
-
# Unpack original docx
|
|
73
62
|
try:
|
|
74
63
|
with zipfile.ZipFile(self.original_docx, "r") as zip_ref:
|
|
75
64
|
zip_ref.extractall(temp_path)
|
|
@@ -84,7 +73,6 @@ class RedliningValidator:
|
|
|
84
73
|
)
|
|
85
74
|
return False
|
|
86
75
|
|
|
87
|
-
# Parse both XML files using xml.etree.ElementTree for redlining validation
|
|
88
76
|
try:
|
|
89
77
|
import xml.etree.ElementTree as ET
|
|
90
78
|
|
|
@@ -96,16 +84,13 @@ class RedliningValidator:
|
|
|
96
84
|
print(f"FAILED - Error parsing XML files: {e}")
|
|
97
85
|
return False
|
|
98
86
|
|
|
99
|
-
# Remove the author's tracked changes from both documents
|
|
100
87
|
self._remove_author_tracked_changes(original_root)
|
|
101
88
|
self._remove_author_tracked_changes(modified_root)
|
|
102
89
|
|
|
103
|
-
# Extract and compare text content
|
|
104
90
|
modified_text = self._extract_text_content(modified_root)
|
|
105
91
|
original_text = self._extract_text_content(original_root)
|
|
106
92
|
|
|
107
93
|
if modified_text != original_text:
|
|
108
|
-
# Show detailed character-level differences for each paragraph
|
|
109
94
|
error_message = self._generate_detailed_diff(
|
|
110
95
|
original_text, modified_text
|
|
111
96
|
)
|
|
@@ -117,7 +102,6 @@ class RedliningValidator:
|
|
|
117
102
|
return True
|
|
118
103
|
|
|
119
104
|
def _generate_detailed_diff(self, original_text, modified_text):
|
|
120
|
-
"""Generate detailed word-level differences using git word diff."""
|
|
121
105
|
error_parts = [
|
|
122
106
|
f"FAILED - Document text doesn't match after removing {self.author}'s tracked changes",
|
|
123
107
|
"",
|
|
@@ -132,7 +116,6 @@ class RedliningValidator:
|
|
|
132
116
|
"",
|
|
133
117
|
]
|
|
134
118
|
|
|
135
|
-
# Show git word diff
|
|
136
119
|
git_diff = self._get_git_word_diff(original_text, modified_text)
|
|
137
120
|
if git_diff:
|
|
138
121
|
error_parts.extend(["Differences:", "============", git_diff])
|
|
@@ -142,26 +125,23 @@ class RedliningValidator:
|
|
|
142
125
|
return "\n".join(error_parts)
|
|
143
126
|
|
|
144
127
|
def _get_git_word_diff(self, original_text, modified_text):
|
|
145
|
-
"""Generate word diff using git with character-level precision."""
|
|
146
128
|
try:
|
|
147
129
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
148
130
|
temp_path = Path(temp_dir)
|
|
149
131
|
|
|
150
|
-
# Create two files
|
|
151
132
|
original_file = temp_path / "original.txt"
|
|
152
133
|
modified_file = temp_path / "modified.txt"
|
|
153
134
|
|
|
154
135
|
original_file.write_text(original_text, encoding="utf-8")
|
|
155
136
|
modified_file.write_text(modified_text, encoding="utf-8")
|
|
156
137
|
|
|
157
|
-
# Try character-level diff first for precise differences
|
|
158
138
|
result = subprocess.run(
|
|
159
139
|
[
|
|
160
140
|
"git",
|
|
161
141
|
"diff",
|
|
162
142
|
"--word-diff=plain",
|
|
163
|
-
"--word-diff-regex=.",
|
|
164
|
-
"-U0",
|
|
143
|
+
"--word-diff-regex=.",
|
|
144
|
+
"-U0",
|
|
165
145
|
"--no-index",
|
|
166
146
|
str(original_file),
|
|
167
147
|
str(modified_file),
|
|
@@ -171,9 +151,7 @@ class RedliningValidator:
|
|
|
171
151
|
)
|
|
172
152
|
|
|
173
153
|
if result.stdout.strip():
|
|
174
|
-
# Clean up the output - remove git diff header lines
|
|
175
154
|
lines = result.stdout.split("\n")
|
|
176
|
-
# Skip the header lines (diff --git, index, +++, ---, @@)
|
|
177
155
|
content_lines = []
|
|
178
156
|
in_content = False
|
|
179
157
|
for line in lines:
|
|
@@ -186,13 +164,12 @@ class RedliningValidator:
|
|
|
186
164
|
if content_lines:
|
|
187
165
|
return "\n".join(content_lines)
|
|
188
166
|
|
|
189
|
-
# Fallback to word-level diff if character-level is too verbose
|
|
190
167
|
result = subprocess.run(
|
|
191
168
|
[
|
|
192
169
|
"git",
|
|
193
170
|
"diff",
|
|
194
171
|
"--word-diff=plain",
|
|
195
|
-
"-U0",
|
|
172
|
+
"-U0",
|
|
196
173
|
"--no-index",
|
|
197
174
|
str(original_file),
|
|
198
175
|
str(modified_file),
|
|
@@ -214,18 +191,15 @@ class RedliningValidator:
|
|
|
214
191
|
return "\n".join(content_lines)
|
|
215
192
|
|
|
216
193
|
except (subprocess.CalledProcessError, FileNotFoundError, Exception):
|
|
217
|
-
# Git not available or other error, return None to use fallback
|
|
218
194
|
pass
|
|
219
195
|
|
|
220
196
|
return None
|
|
221
197
|
|
|
222
198
|
def _remove_author_tracked_changes(self, root):
|
|
223
|
-
"""Remove tracked changes authored by the specified author from the XML root."""
|
|
224
199
|
ins_tag = f"{{{self.namespaces['w']}}}ins"
|
|
225
200
|
del_tag = f"{{{self.namespaces['w']}}}del"
|
|
226
201
|
author_attr = f"{{{self.namespaces['w']}}}author"
|
|
227
202
|
|
|
228
|
-
# Remove w:ins elements
|
|
229
203
|
for parent in root.iter():
|
|
230
204
|
to_remove = []
|
|
231
205
|
for child in parent:
|
|
@@ -234,7 +208,6 @@ class RedliningValidator:
|
|
|
234
208
|
for elem in to_remove:
|
|
235
209
|
parent.remove(elem)
|
|
236
210
|
|
|
237
|
-
# Unwrap content in w:del elements where author matches
|
|
238
211
|
deltext_tag = f"{{{self.namespaces['w']}}}delText"
|
|
239
212
|
t_tag = f"{{{self.namespaces['w']}}}t"
|
|
240
213
|
|
|
@@ -244,36 +217,26 @@ class RedliningValidator:
|
|
|
244
217
|
if child.tag == del_tag and child.get(author_attr) == self.author:
|
|
245
218
|
to_process.append((child, list(parent).index(child)))
|
|
246
219
|
|
|
247
|
-
# Process in reverse order to maintain indices
|
|
248
220
|
for del_elem, del_index in reversed(to_process):
|
|
249
|
-
# Convert w:delText to w:t before moving
|
|
250
221
|
for elem in del_elem.iter():
|
|
251
222
|
if elem.tag == deltext_tag:
|
|
252
223
|
elem.tag = t_tag
|
|
253
224
|
|
|
254
|
-
# Move all children of w:del to its parent before removing w:del
|
|
255
225
|
for child in reversed(list(del_elem)):
|
|
256
226
|
parent.insert(del_index, child)
|
|
257
227
|
parent.remove(del_elem)
|
|
258
228
|
|
|
259
229
|
def _extract_text_content(self, root):
|
|
260
|
-
"""Extract text content from Word XML, preserving paragraph structure.
|
|
261
|
-
|
|
262
|
-
Empty paragraphs are skipped to avoid false positives when tracked
|
|
263
|
-
insertions add only structural elements without text content.
|
|
264
|
-
"""
|
|
265
230
|
p_tag = f"{{{self.namespaces['w']}}}p"
|
|
266
231
|
t_tag = f"{{{self.namespaces['w']}}}t"
|
|
267
232
|
|
|
268
233
|
paragraphs = []
|
|
269
234
|
for p_elem in root.findall(f".//{p_tag}"):
|
|
270
|
-
# Get all text elements within this paragraph
|
|
271
235
|
text_parts = []
|
|
272
236
|
for t_elem in p_elem.findall(f".//{t_tag}"):
|
|
273
237
|
if t_elem.text:
|
|
274
238
|
text_parts.append(t_elem.text)
|
|
275
239
|
paragraph_text = "".join(text_parts)
|
|
276
|
-
# Skip empty paragraphs - they don't affect content validation
|
|
277
240
|
if paragraph_text:
|
|
278
241
|
paragraphs.append(paragraph_text)
|
|
279
242
|
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
1
|
"""
|
|
3
2
|
Excel Formula Recalculation Script
|
|
4
3
|
Recalculates all formulas in an Excel file using LibreOffice
|
|
@@ -15,12 +14,10 @@ from office.soffice import get_soffice_env
|
|
|
15
14
|
|
|
16
15
|
from openpyxl import load_workbook
|
|
17
16
|
|
|
18
|
-
# Platform-specific LibreOffice macro directory
|
|
19
17
|
MACRO_DIR_MACOS = "~/Library/Application Support/LibreOffice/4/user/basic/Standard"
|
|
20
18
|
MACRO_DIR_LINUX = "~/.config/libreoffice/4/user/basic/Standard"
|
|
21
19
|
MACRO_FILENAME = "Module1.xba"
|
|
22
20
|
|
|
23
|
-
# LibreOffice Basic macro for recalculation
|
|
24
21
|
RECALCULATE_MACRO = """<?xml version="1.0" encoding="UTF-8"?>
|
|
25
22
|
<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
|
|
26
23
|
<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Module1" script:language="StarBasic">
|
|
@@ -33,7 +30,6 @@ RECALCULATE_MACRO = """<?xml version="1.0" encoding="UTF-8"?>
|
|
|
33
30
|
|
|
34
31
|
|
|
35
32
|
def has_gtimeout():
|
|
36
|
-
"""Check if gtimeout is available on macOS"""
|
|
37
33
|
try:
|
|
38
34
|
subprocess.run(
|
|
39
35
|
["gtimeout", "--version"], capture_output=True, timeout=1, check=False
|
|
@@ -44,20 +40,17 @@ def has_gtimeout():
|
|
|
44
40
|
|
|
45
41
|
|
|
46
42
|
def setup_libreoffice_macro():
|
|
47
|
-
"""Setup LibreOffice macro for recalculation if not already configured"""
|
|
48
43
|
macro_dir = os.path.expanduser(
|
|
49
44
|
MACRO_DIR_MACOS if platform.system() == "Darwin" else MACRO_DIR_LINUX
|
|
50
45
|
)
|
|
51
46
|
macro_file = os.path.join(macro_dir, MACRO_FILENAME)
|
|
52
47
|
|
|
53
|
-
# Check if macro already exists
|
|
54
48
|
if (
|
|
55
49
|
os.path.exists(macro_file)
|
|
56
50
|
and "RecalculateAndSave" in Path(macro_file).read_text()
|
|
57
51
|
):
|
|
58
52
|
return True
|
|
59
53
|
|
|
60
|
-
# Create macro directory if needed
|
|
61
54
|
if not os.path.exists(macro_dir):
|
|
62
55
|
subprocess.run(
|
|
63
56
|
["soffice", "--headless", "--terminate_after_init"],
|
|
@@ -67,7 +60,6 @@ def setup_libreoffice_macro():
|
|
|
67
60
|
)
|
|
68
61
|
os.makedirs(macro_dir, exist_ok=True)
|
|
69
62
|
|
|
70
|
-
# Write macro file
|
|
71
63
|
try:
|
|
72
64
|
Path(macro_file).write_text(RECALCULATE_MACRO)
|
|
73
65
|
return True
|
|
@@ -76,16 +68,6 @@ def setup_libreoffice_macro():
|
|
|
76
68
|
|
|
77
69
|
|
|
78
70
|
def recalc(filename, timeout=30):
|
|
79
|
-
"""
|
|
80
|
-
Recalculate formulas in Excel file and report any errors
|
|
81
|
-
|
|
82
|
-
Args:
|
|
83
|
-
filename: Path to Excel file
|
|
84
|
-
timeout: Maximum time to wait for recalculation (seconds)
|
|
85
|
-
|
|
86
|
-
Returns:
|
|
87
|
-
dict with error locations and counts
|
|
88
|
-
"""
|
|
89
71
|
if not Path(filename).exists():
|
|
90
72
|
return {"error": f"File {filename} does not exist"}
|
|
91
73
|
|
|
@@ -102,7 +84,6 @@ def recalc(filename, timeout=30):
|
|
|
102
84
|
abs_path,
|
|
103
85
|
]
|
|
104
86
|
|
|
105
|
-
# Wrap command with timeout utility if available
|
|
106
87
|
if platform.system() == "Linux":
|
|
107
88
|
cmd = ["timeout", str(timeout)] + cmd
|
|
108
89
|
elif platform.system() == "Darwin" and has_gtimeout():
|
|
@@ -110,13 +91,12 @@ def recalc(filename, timeout=30):
|
|
|
110
91
|
|
|
111
92
|
result = subprocess.run(cmd, capture_output=True, text=True, env=get_soffice_env())
|
|
112
93
|
|
|
113
|
-
if result.returncode != 0 and result.returncode != 124:
|
|
94
|
+
if result.returncode != 0 and result.returncode != 124:
|
|
114
95
|
error_msg = result.stderr or "Unknown error during recalculation"
|
|
115
96
|
if "Module1" in error_msg or "RecalculateAndSave" not in error_msg:
|
|
116
97
|
return {"error": "LibreOffice macro not configured properly"}
|
|
117
98
|
return {"error": error_msg}
|
|
118
99
|
|
|
119
|
-
# Check for Excel errors in the recalculated file - scan ALL cells
|
|
120
100
|
try:
|
|
121
101
|
wb = load_workbook(filename, data_only=True)
|
|
122
102
|
|
|
@@ -134,7 +114,6 @@ def recalc(filename, timeout=30):
|
|
|
134
114
|
|
|
135
115
|
for sheet_name in wb.sheetnames:
|
|
136
116
|
ws = wb[sheet_name]
|
|
137
|
-
# Check ALL rows and columns - no limits
|
|
138
117
|
for row in ws.iter_rows():
|
|
139
118
|
for cell in row:
|
|
140
119
|
if cell.value is not None and isinstance(cell.value, str):
|
|
@@ -147,22 +126,19 @@ def recalc(filename, timeout=30):
|
|
|
147
126
|
|
|
148
127
|
wb.close()
|
|
149
128
|
|
|
150
|
-
# Build result summary
|
|
151
129
|
result = {
|
|
152
130
|
"status": "success" if total_errors == 0 else "errors_found",
|
|
153
131
|
"total_errors": total_errors,
|
|
154
132
|
"error_summary": {},
|
|
155
133
|
}
|
|
156
134
|
|
|
157
|
-
# Add non-empty error categories
|
|
158
135
|
for err_type, locations in error_details.items():
|
|
159
136
|
if locations:
|
|
160
137
|
result["error_summary"][err_type] = {
|
|
161
138
|
"count": len(locations),
|
|
162
|
-
"locations": locations[:20],
|
|
139
|
+
"locations": locations[:20],
|
|
163
140
|
}
|
|
164
141
|
|
|
165
|
-
# Add formula count for context - also check ALL cells
|
|
166
142
|
wb_formulas = load_workbook(filename, data_only=False)
|
|
167
143
|
formula_count = 0
|
|
168
144
|
for sheet_name in wb_formulas.sheetnames:
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# Make scripts directory a package for relative imports in tests
|
|
File without changes
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Validation modules for Word document processing.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from .base import BaseSchemaValidator
|
|
6
|
-
from .docx import DOCXSchemaValidator
|
|
7
|
-
from .pptx import PPTXSchemaValidator
|
|
8
|
-
from .redlining import RedliningValidator
|
|
9
|
-
|
|
10
|
-
__all__ = [
|
|
11
|
-
"BaseSchemaValidator",
|
|
12
|
-
"DOCXSchemaValidator",
|
|
13
|
-
"PPTXSchemaValidator",
|
|
14
|
-
"RedliningValidator",
|
|
15
|
-
]
|
|
File without changes
|
|
File without changes
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Validation modules for Word document processing.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from .base import BaseSchemaValidator
|
|
6
|
-
from .docx import DOCXSchemaValidator
|
|
7
|
-
from .pptx import PPTXSchemaValidator
|
|
8
|
-
from .redlining import RedliningValidator
|
|
9
|
-
|
|
10
|
-
__all__ = [
|
|
11
|
-
"BaseSchemaValidator",
|
|
12
|
-
"DOCXSchemaValidator",
|
|
13
|
-
"PPTXSchemaValidator",
|
|
14
|
-
"RedliningValidator",
|
|
15
|
-
]
|
|
File without changes
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Validation modules for Word document processing.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from .base import BaseSchemaValidator
|
|
6
|
-
from .docx import DOCXSchemaValidator
|
|
7
|
-
from .pptx import PPTXSchemaValidator
|
|
8
|
-
from .redlining import RedliningValidator
|
|
9
|
-
|
|
10
|
-
__all__ = [
|
|
11
|
-
"BaseSchemaValidator",
|
|
12
|
-
"DOCXSchemaValidator",
|
|
13
|
-
"PPTXSchemaValidator",
|
|
14
|
-
"RedliningValidator",
|
|
15
|
-
]
|
|
File without changes
|