athena-python-docx 0.1.6__tar.gz → 0.1.8__tar.gz
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.
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/PKG-INFO +1 -1
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/docx/__init__.py +1 -1
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/docx/text/paragraph.py +38 -11
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/pyproject.toml +1 -1
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/tests/fidelity/cases.py +1 -1
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/tests/fidelity/runner.py +32 -1
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/.gitignore +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/CLAUDE.md +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/README.md +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/docx/_batching.py +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/docx/api.py +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/docx/client.py +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/docx/document.py +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/docx/enum/__init__.py +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/docx/enum/table.py +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/docx/enum/text.py +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/docx/errors.py +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/docx/shared.py +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/docx/table.py +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/docx/text/__init__.py +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/docx/text/run.py +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/docx/typing.py +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/scripts/publish.sh +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/tests/__init__.py +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/tests/conftest.py +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/tests/fidelity/README.md +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/tests/fidelity/__init__.py +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/tests/fidelity/extract.py +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/tests/test_commands.py +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/tests/test_python_docx_api_parity.py +0 -0
- {athena_python_docx-0.1.6 → athena_python_docx-0.1.8}/tests/test_smoke_integration.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: athena-python-docx
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.8
|
|
4
4
|
Summary: Drop-in replacement for python-docx that connects to Athena's Superdoc/Keryx collaborative document stack
|
|
5
5
|
Project-URL: Homepage, https://athenaintelligence.ai
|
|
6
6
|
Author-email: Athena Intelligence <engineering@athenaintelligence.ai>
|
|
@@ -36,18 +36,38 @@ _STUB_SUFFIX = (
|
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
def _node_text(session: "Session", node_id: str) -> str:
|
|
39
|
-
"""Fetch a block's full text via doc.get_node_by_id.
|
|
39
|
+
"""Fetch a block's full text via doc.get_node_by_id.
|
|
40
|
+
|
|
41
|
+
The response shape for a paragraph is:
|
|
42
|
+
{"node": {"paragraph": {"inlines": [{"run": {"text": "..."}}, ...]}}}
|
|
43
|
+
We concatenate each run's ``text`` in order. Non-paragraph blocks or
|
|
44
|
+
empty responses return ``""``.
|
|
45
|
+
"""
|
|
40
46
|
info: object = run_sync(
|
|
41
47
|
session.doc.get_node_by_id({"id": node_id}),
|
|
42
48
|
)
|
|
43
49
|
if not isinstance(info, dict):
|
|
44
50
|
return ""
|
|
45
51
|
node: object = info.get("node")
|
|
46
|
-
if isinstance(node, dict):
|
|
47
|
-
|
|
52
|
+
if not isinstance(node, dict):
|
|
53
|
+
return ""
|
|
54
|
+
paragraph: object = node.get("paragraph")
|
|
55
|
+
if not isinstance(paragraph, dict):
|
|
56
|
+
return ""
|
|
57
|
+
inlines: object = paragraph.get("inlines")
|
|
58
|
+
if not isinstance(inlines, list):
|
|
59
|
+
return ""
|
|
60
|
+
parts: list[str] = []
|
|
61
|
+
for inline in inlines:
|
|
62
|
+
if not isinstance(inline, dict):
|
|
63
|
+
continue
|
|
64
|
+
run: object = inline.get("run")
|
|
65
|
+
if not isinstance(run, dict):
|
|
66
|
+
continue
|
|
67
|
+
text: object = run.get("text")
|
|
48
68
|
if isinstance(text, str):
|
|
49
|
-
|
|
50
|
-
return ""
|
|
69
|
+
parts.append(text)
|
|
70
|
+
return "".join(parts)
|
|
51
71
|
|
|
52
72
|
|
|
53
73
|
class Paragraph:
|
|
@@ -131,17 +151,24 @@ class Paragraph:
|
|
|
131
151
|
current: str = _node_text(self._session, self._node_id)
|
|
132
152
|
start: int = len(current)
|
|
133
153
|
|
|
134
|
-
#
|
|
135
|
-
#
|
|
136
|
-
#
|
|
154
|
+
# Superdoc expects a selection target with text cursors. A zero-
|
|
155
|
+
# length selection (start == end) is an insertion point, not a
|
|
156
|
+
# replace-range.
|
|
157
|
+
cursor: dict = {
|
|
158
|
+
"kind": "text",
|
|
159
|
+
"blockId": self._node_id,
|
|
160
|
+
"offset": start,
|
|
161
|
+
}
|
|
137
162
|
run_sync(
|
|
138
163
|
self._session.doc.insert(
|
|
139
164
|
{
|
|
165
|
+
"target": {
|
|
166
|
+
"kind": "selection",
|
|
167
|
+
"start": cursor,
|
|
168
|
+
"end": cursor,
|
|
169
|
+
},
|
|
140
170
|
"value": text,
|
|
141
171
|
"type": "text",
|
|
142
|
-
"blockId": self._node_id,
|
|
143
|
-
"start": start,
|
|
144
|
-
"end": start,
|
|
145
172
|
},
|
|
146
173
|
),
|
|
147
174
|
)
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "athena-python-docx"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.8"
|
|
8
8
|
description = "Drop-in replacement for python-docx that connects to Athena's Superdoc/Keryx collaborative document stack"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -119,7 +119,7 @@ CASES: list[Case] = [
|
|
|
119
119
|
),
|
|
120
120
|
Case(
|
|
121
121
|
name="cell_text_setter",
|
|
122
|
-
description="Set cell(0,0).text on a 2x2 table — known NotImplementedError
|
|
122
|
+
description="Set cell(0,0).text on a 2x2 table — known NotImplementedError (Phase 2 stub).",
|
|
123
123
|
script=(
|
|
124
124
|
"t = doc.add_table(rows=2, cols=2)\n"
|
|
125
125
|
't.cell(0, 0).text = "A1"'
|
|
@@ -128,6 +128,10 @@ import os
|
|
|
128
128
|
import traceback
|
|
129
129
|
from pathlib import Path
|
|
130
130
|
|
|
131
|
+
import docx as _docx_mod
|
|
132
|
+
print(f"[sandbox] athena-python-docx __version__ = {{_docx_mod.__version__}}")
|
|
133
|
+
print(f"[sandbox] loaded from {{_docx_mod.__file__}}")
|
|
134
|
+
|
|
131
135
|
OUT_DIR = Path("/tmp/fidelity_out")
|
|
132
136
|
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
|
133
137
|
ASSET_ID = {asset_id!r}
|
|
@@ -295,6 +299,24 @@ async def run_daytona_batch(cases: list[Case], asset_id: str) -> tuple[list[dict
|
|
|
295
299
|
print(f"[fidelity] sandbox {sandbox.id} started")
|
|
296
300
|
|
|
297
301
|
try:
|
|
302
|
+
# Upload the latest-built athena-python-docx wheel so the sandbox runs
|
|
303
|
+
# whichever version is currently in dist/, not the one baked into the
|
|
304
|
+
# image. This keeps the fidelity harness honest during SDK iteration.
|
|
305
|
+
wheel_dir = _SDK_ROOT / "dist"
|
|
306
|
+
wheels = sorted(wheel_dir.glob("athena_python_docx-*.whl"))
|
|
307
|
+
if wheels:
|
|
308
|
+
latest_wheel = wheels[-1]
|
|
309
|
+
await sandbox.fs.upload_file(
|
|
310
|
+
latest_wheel.read_bytes(),
|
|
311
|
+
f"/tmp/{latest_wheel.name}",
|
|
312
|
+
)
|
|
313
|
+
install_cmd = f"pip install --quiet --force-reinstall --no-deps /tmp/{latest_wheel.name}"
|
|
314
|
+
install_res = await sandbox.process.exec(install_cmd, timeout=120)
|
|
315
|
+
print(
|
|
316
|
+
f"[fidelity] installed {latest_wheel.name} "
|
|
317
|
+
f"(exit={install_res.exit_code})",
|
|
318
|
+
)
|
|
319
|
+
|
|
298
320
|
script = build_sandbox_script(cases, asset_id)
|
|
299
321
|
await sandbox.fs.upload_file(script.encode(), "/tmp/fidelity_runner.py")
|
|
300
322
|
exec_result = await sandbox.process.exec(
|
|
@@ -302,6 +324,12 @@ async def run_daytona_batch(cases: list[Case], asset_id: str) -> tuple[list[dict
|
|
|
302
324
|
timeout=600,
|
|
303
325
|
)
|
|
304
326
|
print(f"[fidelity] sandbox exit_code={exec_result.exit_code}")
|
|
327
|
+
# Surface sandbox stdout so [sandbox] diagnostics are visible in the log.
|
|
328
|
+
sandbox_stdout = getattr(exec_result, "result", None) or ""
|
|
329
|
+
if sandbox_stdout:
|
|
330
|
+
print("─── sandbox stdout ─────────────────────────────────")
|
|
331
|
+
print(sandbox_stdout)
|
|
332
|
+
print("────────────────────────────────────────────────────")
|
|
305
333
|
# Load the results JSON
|
|
306
334
|
raw = await sandbox.fs.download_file("/tmp/fidelity_results.json")
|
|
307
335
|
results: list[dict] = json.loads(raw.decode())
|
|
@@ -341,7 +369,10 @@ def print_scorecard(
|
|
|
341
369
|
"""Print a scorecard. Return exit code (0 = all green)."""
|
|
342
370
|
print()
|
|
343
371
|
print("=" * 88)
|
|
344
|
-
|
|
372
|
+
from docx import __version__ as _sdk_version
|
|
373
|
+
print(
|
|
374
|
+
f"FIDELITY SCORECARD — athena-python-docx {_sdk_version} vs stock python-docx",
|
|
375
|
+
)
|
|
345
376
|
print("=" * 88)
|
|
346
377
|
|
|
347
378
|
by_name = {r["name"]: r for r in daytona_results}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|