licos-dev-cli 0.4.2__tar.gz → 0.4.3__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.
- {licos_dev_cli-0.4.2 → licos_dev_cli-0.4.3}/PKG-INFO +2 -2
- {licos_dev_cli-0.4.2 → licos_dev_cli-0.4.3}/pyproject.toml +2 -2
- {licos_dev_cli-0.4.2 → licos_dev_cli-0.4.3}/src/licos_dev_cli/docx_commands.py +19 -6
- {licos_dev_cli-0.4.2 → licos_dev_cli-0.4.3}/src/licos_dev_cli/main.py +1 -0
- {licos_dev_cli-0.4.2 → licos_dev_cli-0.4.3}/tests/test_docx_commands.py +43 -0
- {licos_dev_cli-0.4.2 → licos_dev_cli-0.4.3}/.gitignore +0 -0
- {licos_dev_cli-0.4.2 → licos_dev_cli-0.4.3}/src/licos_dev_cli/__init__.py +0 -0
- {licos_dev_cli-0.4.2 → licos_dev_cli-0.4.3}/src/licos_dev_cli/common.py +0 -0
- {licos_dev_cli-0.4.2 → licos_dev_cli-0.4.3}/src/licos_dev_cli/docx_legacy.py +0 -0
- {licos_dev_cli-0.4.2 → licos_dev_cli-0.4.3}/src/licos_dev_cli/ppt_master.py +0 -0
- {licos_dev_cli-0.4.2 → licos_dev_cli-0.4.3}/tests/test_cli_output_paths.py +0 -0
- {licos_dev_cli-0.4.2 → licos_dev_cli-0.4.3}/tests/test_credit_check.py +0 -0
- {licos_dev_cli-0.4.2 → licos_dev_cli-0.4.3}/tests/test_document_read_cli.py +0 -0
- {licos_dev_cli-0.4.2 → licos_dev_cli-0.4.3}/tests/test_ppt_master_cli.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: licos-dev-cli
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.3
|
|
4
4
|
Summary: LICOS Dev CLI - generate files and call model capabilities
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Requires-Dist: click>=8.1
|
|
7
|
-
Requires-Dist: licos-dev-sdk>=0.4.
|
|
7
|
+
Requires-Dist: licos-dev-sdk>=0.4.3
|
|
@@ -4,11 +4,11 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "licos-dev-cli"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.3"
|
|
8
8
|
description = "LICOS Dev CLI - generate files and call model capabilities"
|
|
9
9
|
requires-python = ">=3.10"
|
|
10
10
|
dependencies = [
|
|
11
|
-
"licos-dev-sdk>=0.4.
|
|
11
|
+
"licos-dev-sdk>=0.4.3",
|
|
12
12
|
"click>=8.1",
|
|
13
13
|
]
|
|
14
14
|
|
|
@@ -55,7 +55,7 @@ def text_input(value, path, name):
|
|
|
55
55
|
|
|
56
56
|
@click.command("docx-structure")
|
|
57
57
|
@click.option("--file", "source", required=True, type=click.Path(exists=True, dir_okay=False))
|
|
58
|
-
@click.option("--scope", type=click.Choice(["blocks", "paragraphs"]), default="blocks", show_default=True)
|
|
58
|
+
@click.option("--scope", type=click.Choice(["blocks", "paragraphs", "tables"]), default="blocks", show_default=True)
|
|
59
59
|
@click.option("--offset", type=click.IntRange(min=1), default=1, show_default=True)
|
|
60
60
|
@click.option("--limit", type=click.IntRange(1, 200), default=20, show_default=True)
|
|
61
61
|
@click.option("--max-chars", type=click.IntRange(1, 8000), default=200, show_default=True)
|
|
@@ -141,7 +141,8 @@ def docx_table_set(text, text_file, **arguments):
|
|
|
141
141
|
@click.command("docx-table-insert-rows")
|
|
142
142
|
@edit_options
|
|
143
143
|
@click.option("--table", required=True, type=click.IntRange(min=1))
|
|
144
|
-
@click.option("--before",
|
|
144
|
+
@click.option("--before", type=click.IntRange(min=1), help="Insert before this one-based row. Choose --before or --append.")
|
|
145
|
+
@click.option("--append", is_flag=True, help="Append after the last row; no row count calculation needed.")
|
|
145
146
|
@click.option("--template-row", required=True, type=click.IntRange(min=1), help="Existing styled row; must not intersect a vertical merge.")
|
|
146
147
|
@click.option("--input", "input_path", required=True, type=click.Path(exists=True, dir_okay=False), help="Two-dimensional JSON array of scalar values. Fill a merged cell once; count is inferred.")
|
|
147
148
|
@sdk_errors
|
|
@@ -153,17 +154,29 @@ def docx_table_insert_rows(input_path, **arguments):
|
|
|
153
154
|
|
|
154
155
|
@click.command("docx-verify")
|
|
155
156
|
@click.option("--file", "source", required=True, type=click.Path(exists=True, dir_okay=False))
|
|
157
|
+
@click.option("--original", type=click.Path(exists=True, dir_okay=False), help="Compare non-body package parts (headers, footers, styles, images) and section settings with the original.")
|
|
156
158
|
@click.option("--input", "input_path", type=click.Path(exists=True, dir_okay=False), help="JSON array of target/text assertions and optional mode (equals, contains, absent).")
|
|
159
|
+
@target_options
|
|
160
|
+
@click.option("--text", default=None, help="Expected text at one target; use this or --text-file instead of --input.")
|
|
161
|
+
@click.option("--text-file", type=click.Path(exists=True, dir_okay=False), help="UTF-8 expected text; preserves whitespace and line breaks.")
|
|
162
|
+
@click.option("--mode", type=click.Choice(["equals", "contains", "absent"]), help="Single-target comparison; defaults to equals.")
|
|
157
163
|
@sdk_errors
|
|
158
|
-
def docx_verify(source, input_path):
|
|
159
|
-
"""Verify exact positions
|
|
164
|
+
def docx_verify(source, original, input_path, paragraph, block, table, row, column, text, text_file, mode):
|
|
165
|
+
"""Verify exact positions and optional original parts. No assertions means no content verification.
|
|
160
166
|
|
|
161
167
|
Example: [{"target":{"table":1,"row":1,"column":1},"text":"Supplier: A"}]
|
|
162
168
|
|
|
163
|
-
Exits 2 if an assertion fails. Does not certify rendered page layout.
|
|
169
|
+
Exits 2 if an assertion or original comparison fails. Does not certify rendered page layout.
|
|
164
170
|
"""
|
|
165
171
|
from licos_dev_sdk import verify_docx
|
|
166
|
-
|
|
172
|
+
position = target(paragraph, block, table, row, column)
|
|
173
|
+
single = bool(position) or text is not None or text_file is not None or mode is not None
|
|
174
|
+
if input_path is not None and single:
|
|
175
|
+
raise click.UsageError("use --input or a single target with --text/--text-file, not both")
|
|
176
|
+
expectations = json.loads(Path(input_path).read_text(encoding="utf-8")) if input_path else None
|
|
177
|
+
if single:
|
|
178
|
+
expectations = [{"target": position, "text": text_input(text, text_file, "text"), "mode": mode or "equals"}]
|
|
179
|
+
report = verify_docx(source, original=original, expectations=expectations)
|
|
167
180
|
result(report)
|
|
168
181
|
if not report["verified"]:
|
|
169
182
|
raise click.exceptions.Exit(2)
|
|
@@ -14,6 +14,7 @@ from .common import _read_input, _read_json, _json_option, _echo_json, _path_to_
|
|
|
14
14
|
# ── CLI Group ────────────────────────────────────────────────────────────────
|
|
15
15
|
|
|
16
16
|
@click.group()
|
|
17
|
+
@click.version_option(package_name="licos-dev-cli")
|
|
17
18
|
def cli():
|
|
18
19
|
"""LICOS Dev - file generation and model CLI for AI agents."""
|
|
19
20
|
pass
|
|
@@ -81,3 +81,46 @@ def test_command_help_is_focused_and_preserves_constraints():
|
|
|
81
81
|
assert len(help_text.output.encode("utf-8")) < 5000
|
|
82
82
|
help_text = runner.invoke(cli, ["docx-table-insert-rows", "--help"]).output
|
|
83
83
|
assert "--revision" in help_text and "--template-row" in help_text and "--count" not in help_text
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_append_and_verify_with_original_and_text_file(source, tmp_path):
|
|
87
|
+
rows = tmp_path / "rows.json"
|
|
88
|
+
rows.write_text('[["pump",2]]', encoding="utf-8")
|
|
89
|
+
output = tmp_path / "rows.docx"
|
|
90
|
+
read = invoke("docx-structure", "--file", source, "--scope", "tables")
|
|
91
|
+
assert read["items"][0]["row_count"] == 1
|
|
92
|
+
invoke("docx-table-insert-rows", "--source", source, "--output", output, "--revision", read["revision"],
|
|
93
|
+
"--table", 1, "--append", "--template-row", 1, "--input", rows)
|
|
94
|
+
assert invoke("docx-verify", "--file", output, "--original", source, "--table", 1, "--row", 2, "--column", 1, "--text", "pump")["verified"]
|
|
95
|
+
replacement = tmp_path / "text.txt"
|
|
96
|
+
text = " 中文🙂\t空格\n" * 100 + " "
|
|
97
|
+
replacement.write_text(text, encoding="utf-8")
|
|
98
|
+
invoke("docx-replace", "--source", output, "--output", output, "--overwrite",
|
|
99
|
+
"--revision", invoke("docx-structure", "--file", output)["revision"],
|
|
100
|
+
"--block", 1, "--search", "账号:123", "--replace-file", replacement)
|
|
101
|
+
verified = invoke("docx-verify", "--file", output, "--original", source, "--block", 1, "--text-file", replacement)
|
|
102
|
+
assert verified["content_verified"] and verified["preservation_verified"]
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@pytest.mark.parametrize("arguments", [
|
|
106
|
+
["--block", "1"], ["--text", "x"], ["--mode", "contains"],
|
|
107
|
+
["--block", "1", "--text", "x", "--input", "checks.json"],
|
|
108
|
+
["--block", "1", "--text", "x", "--text-file", "text.txt"],
|
|
109
|
+
])
|
|
110
|
+
def test_invalid_verification_options_are_reported(source, tmp_path, monkeypatch, arguments):
|
|
111
|
+
monkeypatch.chdir(tmp_path)
|
|
112
|
+
(tmp_path / "checks.json").write_text("[]", encoding="utf-8")
|
|
113
|
+
(tmp_path / "text.txt").write_text("x", encoding="utf-8")
|
|
114
|
+
result = CliRunner().invoke(cli, ["docx-verify", "--file", str(source), *arguments])
|
|
115
|
+
assert result.exit_code != 0
|
|
116
|
+
assert "Error:" in result.output
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_original_comparison_failure_exits_two(source, tmp_path):
|
|
120
|
+
changed = tmp_path / "changed.docx"
|
|
121
|
+
doc = Document(source)
|
|
122
|
+
doc.sections[0].footer.paragraphs[0].text = "changed footer"
|
|
123
|
+
doc.save(changed)
|
|
124
|
+
failure = CliRunner().invoke(cli, ["docx-verify", "--file", str(changed), "--original", str(source)])
|
|
125
|
+
assert failure.exit_code == 2
|
|
126
|
+
assert not json.loads(failure.output)["preservation_verified"]
|
|
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
|