licos-dev-cli 0.3.9__tar.gz → 0.4.0__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.
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: licos-dev-cli
3
- Version: 0.3.9
3
+ Version: 0.4.0
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.3.9
7
+ Requires-Dist: licos-dev-sdk>=0.4.0
@@ -4,11 +4,11 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "licos-dev-cli"
7
- version = "0.3.9"
7
+ version = "0.4.0"
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.3.9",
11
+ "licos-dev-sdk>=0.4.0",
12
12
  "click>=8.1",
13
13
  ]
14
14
 
@@ -251,16 +251,41 @@ def docx_template(template_path, input_path, data_content, filename, output_dir)
251
251
  _echo_path(path)
252
252
 
253
253
 
254
+ @cli.command("docx-edit")
255
+ @click.option("-s", "--source", "source_path", required=True, type=click.Path(exists=True, dir_okay=False))
256
+ @click.option("-i", "--input", "input_path", help="JSON operation file")
257
+ @click.option("-d", "--data", "data_content", help="JSON operation array")
258
+ @click.option("-f", "--filename", required=True)
259
+ @click.option("-o", "--output-dir", default=None)
260
+ def docx_edit(source_path, input_path, data_content, filename, output_dir):
261
+ """Edit native tables in an existing DOCX package."""
262
+ from licos_dev_sdk import edit_docx
263
+
264
+ payload = _read_json(input_path, data_content)
265
+ operations = payload.get("operations") if isinstance(payload, dict) else payload
266
+ if not isinstance(operations, list):
267
+ raise click.BadParameter("operations must be a JSON array or an object containing operations")
268
+ path = edit_docx(source_path, operations, filename, output_dir=output_dir)
269
+ _echo_path(path)
270
+
271
+
254
272
  @cli.command("docx-read")
255
273
  @click.option("-f", "--file", "file_path", required=True, type=click.Path(exists=True, dir_okay=False))
256
274
  @click.option("--offset", type=click.IntRange(min=1), default=1, show_default=True)
257
275
  @click.option("--limit", type=click.IntRange(min=1), default=20, show_default=True)
258
276
  @click.option("--max-chars", type=click.IntRange(min=256), default=8_000, show_default=True)
259
- def docx_read(file_path, offset, limit, max_chars):
277
+ @click.option("--include-styles", is_flag=True, help="Include paragraph, run, row, and cell styles")
278
+ def docx_read(file_path, offset, limit, max_chars, include_styles):
260
279
  """Read DOCX paragraphs and table rows as paginated JSON."""
261
280
  from licos_dev_sdk import read_docx
262
281
 
263
- report = read_docx(file_path, offset=offset, limit=limit, max_chars=max_chars)
282
+ report = read_docx(
283
+ file_path,
284
+ offset=offset,
285
+ limit=limit,
286
+ max_chars=max_chars,
287
+ include_styles=include_styles,
288
+ )
264
289
  report["path"] = _path_to_cli_output(report["path"])
265
290
  _echo_json(report)
266
291
 
@@ -275,11 +300,41 @@ def docx_read(file_path, offset, limit, max_chars):
275
300
  @click.option("--sheet-name", default="Sheet1")
276
301
  @click.option("--header-color", default="4472C4")
277
302
  @click.option("--theme", default="professional-blue", help="Theme: professional-blue|business|neutral")
278
- def xlsx(input_path, content, filename, output_dir, sheet_name, header_color, theme):
279
- """Generate XLSX from JSON data."""
280
- from licos_dev_sdk import create_xlsx
281
- data = _read_json(input_path, content)
282
- path = create_xlsx(data, filename, output_dir=output_dir, sheet_name=sheet_name, header_color=header_color, theme=theme)
303
+ @click.option("--format", "content_type", type=click.Choice(["json", "html", "docx"]), default="json", show_default=True)
304
+ @click.option("--column", "columns", multiple=True, help="Exact DOCX table header; repeat for each output column")
305
+ def xlsx(input_path, content, filename, output_dir, sheet_name, header_color, theme, content_type, columns):
306
+ """Generate native XLSX from JSON, HTML, or selected DOCX table columns."""
307
+ if content_type == "docx":
308
+ from licos_dev_sdk import create_xlsx_from_docx
309
+
310
+ if not input_path:
311
+ raise click.BadParameter("--input is required for DOCX input", param_hint="--input")
312
+ if content is not None:
313
+ raise click.BadParameter("--content is not supported for DOCX input", param_hint="--content")
314
+ if not columns:
315
+ raise click.BadParameter("at least one --column is required for DOCX input", param_hint="--column")
316
+ path = create_xlsx_from_docx(
317
+ input_path,
318
+ columns,
319
+ filename,
320
+ output_dir=output_dir,
321
+ sheet_name=sheet_name,
322
+ theme=theme,
323
+ )
324
+ elif content_type == "html":
325
+ from licos_dev_sdk import create_xlsx_from_html
326
+
327
+ path = create_xlsx_from_html(
328
+ _read_input(input_path, content),
329
+ filename,
330
+ output_dir=output_dir,
331
+ sheet_name=sheet_name,
332
+ )
333
+ else:
334
+ from licos_dev_sdk import create_xlsx
335
+
336
+ data = _read_json(input_path, content)
337
+ path = create_xlsx(data, filename, output_dir=output_dir, sheet_name=sheet_name, header_color=header_color, theme=theme)
283
338
  _echo_path(path)
284
339
 
285
340
 
@@ -324,7 +379,8 @@ def xlsx_inspect(file_path):
324
379
  @click.option("--offset", type=click.IntRange(min=1), default=1, show_default=True)
325
380
  @click.option("--limit", type=click.IntRange(min=1), default=20, show_default=True)
326
381
  @click.option("--max-chars", type=click.IntRange(min=256), default=8_000, show_default=True)
327
- def xlsx_read(file_path, sheet, cell_range, offset, limit, max_chars):
382
+ @click.option("--include-styles", is_flag=True, help="Include cell number, font, fill, and alignment styles")
383
+ def xlsx_read(file_path, sheet, cell_range, offset, limit, max_chars, include_styles):
328
384
  """List XLSX worksheets or read rows from a selected worksheet."""
329
385
  from licos_dev_sdk import read_xlsx
330
386
 
@@ -335,11 +391,30 @@ def xlsx_read(file_path, sheet, cell_range, offset, limit, max_chars):
335
391
  offset=offset,
336
392
  limit=limit,
337
393
  max_chars=max_chars,
394
+ include_styles=include_styles,
338
395
  )
339
396
  report["path"] = _path_to_cli_output(report["path"])
340
397
  _echo_json(report)
341
398
 
342
399
 
400
+ @cli.command("xlsx-edit")
401
+ @click.option("-s", "--source", "source_path", required=True, type=click.Path(exists=True, dir_okay=False))
402
+ @click.option("-i", "--input", "input_path", help="JSON operation file")
403
+ @click.option("-d", "--data", "data_content", help="JSON operation array")
404
+ @click.option("-f", "--filename", required=True)
405
+ @click.option("-o", "--output-dir", default=None)
406
+ def xlsx_edit(source_path, input_path, data_content, filename, output_dir):
407
+ """Edit an existing native XLSX workbook."""
408
+ from licos_dev_sdk import edit_xlsx
409
+
410
+ payload = _read_json(input_path, data_content)
411
+ operations = payload.get("operations") if isinstance(payload, dict) else payload
412
+ if not isinstance(operations, list):
413
+ raise click.BadParameter("operations must be a JSON array or an object containing operations")
414
+ path = edit_xlsx(source_path, operations, filename, output_dir=output_dir)
415
+ _echo_path(path)
416
+
417
+
343
418
  # ── CSV ──────────────────────────────────────────────────────────────────────
344
419
 
345
420
  @cli.command()
@@ -46,3 +46,52 @@ def test_xlsx_read_without_sheet_returns_workbook_structure(tmp_path: Path):
46
46
  payload = json.loads(result.output)
47
47
  assert payload["mode"] == "workbook_overview"
48
48
  assert payload["sheet_names"] == ["Overview", "Details"]
49
+
50
+
51
+ def test_xlsx_command_extracts_selected_docx_columns(tmp_path: Path, monkeypatch):
52
+ from docx import Document
53
+ from openpyxl import load_workbook
54
+
55
+ project = tmp_path / "projects"
56
+ project.mkdir()
57
+ source = project / "source.docx"
58
+ document = Document()
59
+ table = document.add_table(rows=2, cols=4)
60
+ for column, value in enumerate(["序号", "名称", "单位", "数量"]):
61
+ table.cell(0, column).text = value
62
+ for column, value in enumerate(["1", "泵", "台", "2"]):
63
+ table.cell(1, column).text = value
64
+ document.save(source)
65
+ monkeypatch.setenv("LICOS_PROJECT_PATH", str(project))
66
+
67
+ result = CliRunner().invoke(
68
+ cli,
69
+ [
70
+ "xlsx",
71
+ "--format",
72
+ "docx",
73
+ "--input",
74
+ str(source),
75
+ "--column",
76
+ "名称",
77
+ "--column",
78
+ "单位",
79
+ "--column",
80
+ "数量",
81
+ "--filename",
82
+ "result",
83
+ "--output-dir",
84
+ str(project),
85
+ ],
86
+ )
87
+
88
+ assert result.exit_code == 0, result.output
89
+ assert result.output.strip() == "result.xlsx"
90
+ workbook = load_workbook(project / "result.xlsx")
91
+ try:
92
+ assert list(workbook.active.values) == [
93
+ ("名称", "单位", "数量"),
94
+ ("泵", "台", "2"),
95
+ ]
96
+ finally:
97
+ workbook.close()
File without changes