pptx-cli 1.2.6__tar.gz → 1.3.1__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.
- pptx_cli-1.3.1/.claude/settings.local.json +7 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/PKG-INFO +1 -1
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/__init__.py +1 -1
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/cli.py +22 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/commands/guide.py +10 -0
- pptx_cli-1.3.1/src/pptx_cli/commands/schema.py +227 -0
- pptx_cli-1.3.1/tests/test_schema.py +80 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/.editorconfig +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/.github/copilot-instructions.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/.github/instructions/backend.instructions.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/.github/instructions/testing.instructions.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/.github/skills/pptx/SKILL.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/.github/skills/pptx/references/deck-spec.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/.github/skills/pptx-deck-builder/SKILL.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/.github/skills/pptx-deck-builder/references/excal-diagrams.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/.github/skills/pptx-deck-builder/references/mckinsey-style.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/.github/skills/pptx-deck-builder/references/pptx-workflow.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/.github/workflows/ci.yml +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/.github/workflows/publish.yml +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/.gitignore +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/.python-version +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/AGENTS.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/ARCHITECTURE.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/CHANGELOG.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/CLI-MANIFEST.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/CONTRIBUTING.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/DECISIONS/ADR-0001-initial-architecture.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/LICENSE +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/PRD.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/PREVIEW-FUTURE.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/PROJECT.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/README.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/SCAFFOLD.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/SECURITY.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/TESTING.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/docs/DOMAIN.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/docs/GLOSSARY.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/docs/ROADMAP.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/docs/SCAFFOLDING-NOTES.md +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/guardrails/.gitignore +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/guardrails/guardrails.jsonl +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/guardrails/links.jsonl +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/guardrails/references.jsonl +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/guardrails/taxonomy.json +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/guardrails-explorer.html +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/pyproject.toml +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/pyrightconfig.json +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/scripts/bump_version.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/__main__.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/commands/__init__.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/commands/compose.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/commands/init.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/commands/inspect.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/commands/manifest_ops.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/commands/validate.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/commands/wrapper.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/core/__init__.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/core/composition.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/core/ids.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/core/io.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/core/manifest_store.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/core/markdown.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/core/runtime.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/core/template.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/core/validation.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/core/versioning.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/models/__init__.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/models/envelope.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/src/pptx_cli/models/manifest.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/tests/conftest.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/tests/test_cli.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/tests/test_versioning.py +0 -0
- {pptx_cli-1.2.6 → pptx_cli-1.3.1}/uv.lock +0 -0
|
@@ -20,6 +20,7 @@ from pptx_cli.commands.inspect import (
|
|
|
20
20
|
show_theme,
|
|
21
21
|
)
|
|
22
22
|
from pptx_cli.commands.manifest_ops import manifest_diff, manifest_schema
|
|
23
|
+
from pptx_cli.commands.schema import build_schema_document, copy_to_clipboard
|
|
23
24
|
from pptx_cli.commands.validate import validate_command
|
|
24
25
|
from pptx_cli.commands.wrapper import wrapper_generate
|
|
25
26
|
from pptx_cli.core.composition import CompositionError
|
|
@@ -238,6 +239,27 @@ def guide(format: FormatOption = None) -> None:
|
|
|
238
239
|
execute("guide.show", format, lambda: build_guide_document().model_dump(mode="json"))
|
|
239
240
|
|
|
240
241
|
|
|
242
|
+
@app.command("schema")
|
|
243
|
+
def schema_command(
|
|
244
|
+
template: Annotated[
|
|
245
|
+
Path | None,
|
|
246
|
+
typer.Option("--template", help="Path to a manifest package directory."),
|
|
247
|
+
] = None,
|
|
248
|
+
no_copy: Annotated[
|
|
249
|
+
bool,
|
|
250
|
+
typer.Option("--no-copy", help="Skip copying output to the clipboard."),
|
|
251
|
+
] = False,
|
|
252
|
+
) -> None:
|
|
253
|
+
"""Print the deck-spec YAML reference (for pasting into LLM prompts)."""
|
|
254
|
+
text = build_schema_document(template)
|
|
255
|
+
typer.echo(text)
|
|
256
|
+
if not no_copy:
|
|
257
|
+
if copy_to_clipboard(text):
|
|
258
|
+
typer.echo("(copied to clipboard)", err=True)
|
|
259
|
+
else:
|
|
260
|
+
typer.echo("(clipboard copy failed – install xclip or pipe manually)", err=True)
|
|
261
|
+
|
|
262
|
+
|
|
241
263
|
@app.command("init")
|
|
242
264
|
def init_command(
|
|
243
265
|
template: Annotated[Path, typer.Argument(help="Path to the source .pptx template")],
|
|
@@ -17,6 +17,16 @@ def build_guide_document() -> GuideDocument:
|
|
|
17
17
|
mutates=False,
|
|
18
18
|
examples=["pptx guide --format json"],
|
|
19
19
|
),
|
|
20
|
+
GuideCommand(
|
|
21
|
+
id="schema.show",
|
|
22
|
+
summary="Print the deck-spec YAML reference for pasting into LLM prompts",
|
|
23
|
+
mutates=False,
|
|
24
|
+
examples=[
|
|
25
|
+
"pptx schema",
|
|
26
|
+
"pptx schema --template ./corp-template",
|
|
27
|
+
"pptx schema --no-copy",
|
|
28
|
+
],
|
|
29
|
+
),
|
|
20
30
|
GuideCommand(
|
|
21
31
|
id="template.init",
|
|
22
32
|
summary="Initialize a manifest package from a source template",
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"""Build a human-readable YAML reference for deck specs.
|
|
2
|
+
|
|
3
|
+
Designed to be pasted into LLM prompts so the model knows how to
|
|
4
|
+
author valid ``pptx deck build`` input.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import subprocess
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
import yaml
|
|
15
|
+
|
|
16
|
+
from pptx_cli.core.manifest_store import load_effective_manifest
|
|
17
|
+
from pptx_cli.models.manifest import LayoutContract, ManifestDocument
|
|
18
|
+
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
|
+
# Clipboard helper
|
|
21
|
+
# ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def copy_to_clipboard(text: str) -> bool:
|
|
25
|
+
"""Copy *text* to the system clipboard. Returns True on success."""
|
|
26
|
+
if sys.platform == "win32":
|
|
27
|
+
cmd = ["clip"]
|
|
28
|
+
elif sys.platform == "darwin":
|
|
29
|
+
cmd = ["pbcopy"]
|
|
30
|
+
else:
|
|
31
|
+
cmd = ["xclip", "-selection", "clipboard"]
|
|
32
|
+
try:
|
|
33
|
+
subprocess.run(
|
|
34
|
+
cmd,
|
|
35
|
+
input=text.encode("utf-8"),
|
|
36
|
+
check=True,
|
|
37
|
+
timeout=5,
|
|
38
|
+
)
|
|
39
|
+
except (FileNotFoundError, subprocess.SubprocessError):
|
|
40
|
+
return False
|
|
41
|
+
return True
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# ---------------------------------------------------------------------------
|
|
45
|
+
# Generic (template-free) schema
|
|
46
|
+
# ---------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
_GENERIC_SCHEMA = """\
|
|
49
|
+
<slide-schema>
|
|
50
|
+
Use this schema to draft presentation content. Layout assignment and
|
|
51
|
+
template binding happen later, so focus on the slides themselves.
|
|
52
|
+
|
|
53
|
+
metadata:
|
|
54
|
+
title: "<deck title>"
|
|
55
|
+
author: "<author name>"
|
|
56
|
+
|
|
57
|
+
slides:
|
|
58
|
+
- title: "Slide heading"
|
|
59
|
+
body: |
|
|
60
|
+
- Bullet one
|
|
61
|
+
- Bullet two
|
|
62
|
+
notes: |
|
|
63
|
+
Talk track for this slide.
|
|
64
|
+
|
|
65
|
+
- title: "Data slide"
|
|
66
|
+
body: |
|
|
67
|
+
Key observations from the quarter.
|
|
68
|
+
table:
|
|
69
|
+
kind: table
|
|
70
|
+
columns: [Col A, Col B]
|
|
71
|
+
rows:
|
|
72
|
+
- [val1, val2]
|
|
73
|
+
- [val3, val4]
|
|
74
|
+
notes: Additional context.
|
|
75
|
+
|
|
76
|
+
- title: "Trend slide"
|
|
77
|
+
body: |
|
|
78
|
+
Revenue grew 50% year-over-year.
|
|
79
|
+
chart:
|
|
80
|
+
kind: chart
|
|
81
|
+
chart_type: column_clustered
|
|
82
|
+
categories: [Q1, Q2, Q3]
|
|
83
|
+
series:
|
|
84
|
+
- name: Revenue
|
|
85
|
+
values: [12, 15, 18]
|
|
86
|
+
|
|
87
|
+
- title: "Visual slide"
|
|
88
|
+
image:
|
|
89
|
+
kind: image
|
|
90
|
+
path: path/to/image.png
|
|
91
|
+
image_fit: fit
|
|
92
|
+
</slide-schema>
|
|
93
|
+
|
|
94
|
+
<content-rules>
|
|
95
|
+
- Each slide MUST have a "title".
|
|
96
|
+
- Use "body" for the main text area. Markdown is auto-detected
|
|
97
|
+
(headings, bullets, **bold**, *italic*).
|
|
98
|
+
- Use "table", "chart", or "image" keys for structured content.
|
|
99
|
+
chart_type accepts: column_clustered, bar_clustered, line, pie.
|
|
100
|
+
image_fit accepts: "fit" (default) or "cover".
|
|
101
|
+
- "notes" is optional speaker-notes text (markdown ok).
|
|
102
|
+
- Do NOT include a "layout" key - layout is assigned later when
|
|
103
|
+
binding to a corporate template.
|
|
104
|
+
</content-rules>
|
|
105
|
+
|
|
106
|
+
<style-guide>
|
|
107
|
+
Follow these principles to produce decision-grade slides.
|
|
108
|
+
|
|
109
|
+
Structure
|
|
110
|
+
- Lead with the answer. Do not build up to the conclusion.
|
|
111
|
+
- Pyramid Principle: governing thought -> supporting arguments -> evidence.
|
|
112
|
+
- Arguments must be MECE (mutually exclusive, collectively exhaustive).
|
|
113
|
+
- One slide = one message. Two insights -> two slides.
|
|
114
|
+
|
|
115
|
+
Titles
|
|
116
|
+
- Use action titles, not topic labels. The title states the takeaway.
|
|
117
|
+
Bad: "Market overview"
|
|
118
|
+
Good: "Nordic retail banking margins will remain under pressure through 2027"
|
|
119
|
+
- Title storyline reads on its own - skim only titles and understand the
|
|
120
|
+
full argument.
|
|
121
|
+
- Formulas:
|
|
122
|
+
Insight: "[What happened] because [driver]"
|
|
123
|
+
Comparison: "[A] outperforms [B] on [criterion]"
|
|
124
|
+
Implication: "[Fact] puts [objective] at risk"
|
|
125
|
+
Recommendation: "[Org] should [action] to achieve [outcome]"
|
|
126
|
+
|
|
127
|
+
Executive summary slide
|
|
128
|
+
- Situation: what context everyone agrees on.
|
|
129
|
+
- Complication: what changed or created urgency.
|
|
130
|
+
- Answer: the recommended response.
|
|
131
|
+
- Support: 2-3 reasons the answer is correct.
|
|
132
|
+
|
|
133
|
+
Deck sequence (typical)
|
|
134
|
+
1. Title page
|
|
135
|
+
2. Executive summary (situation -> complication -> resolution)
|
|
136
|
+
3. Context / problem framing (only enough to orient)
|
|
137
|
+
4. Analysis body (current state -> root causes -> options -> recommendation)
|
|
138
|
+
5. Recommendation (explicit, decision-ready)
|
|
139
|
+
6. Implementation / roadmap
|
|
140
|
+
7. Risks and mitigations
|
|
141
|
+
8. Appendix (source data, benchmarks, methodology)
|
|
142
|
+
|
|
143
|
+
Body content
|
|
144
|
+
- Every claim backed by evidence. The body proves the headline.
|
|
145
|
+
- Quantify. Replace vague adjectives with measured claims.
|
|
146
|
+
- Keep text tight: verbs, short bullets, no filler.
|
|
147
|
+
- Move backup detail to appendix - main story stays focused.
|
|
148
|
+
</style-guide>
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# ---------------------------------------------------------------------------
|
|
153
|
+
# Template-enriched schema
|
|
154
|
+
# ---------------------------------------------------------------------------
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _placeholder_summary(ph: Any) -> dict[str, Any]:
|
|
158
|
+
"""Compact summary of a placeholder contract."""
|
|
159
|
+
entry: dict[str, Any] = {
|
|
160
|
+
"types": ph.supported_content_types,
|
|
161
|
+
}
|
|
162
|
+
if ph.required:
|
|
163
|
+
entry["required"] = True
|
|
164
|
+
if ph.guidance_text:
|
|
165
|
+
entry["guidance"] = ph.guidance_text
|
|
166
|
+
cap = ph.estimated_text_capacity
|
|
167
|
+
if cap is not None:
|
|
168
|
+
entry["max_lines"] = cap.max_lines
|
|
169
|
+
return entry
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _layout_section(layout: LayoutContract) -> dict[str, Any]:
|
|
173
|
+
"""Build a dict describing one layout for the reference doc."""
|
|
174
|
+
section: dict[str, Any] = {}
|
|
175
|
+
if layout.description:
|
|
176
|
+
section["description"] = layout.description
|
|
177
|
+
if layout.aliases:
|
|
178
|
+
section["aliases"] = layout.aliases
|
|
179
|
+
placeholders: dict[str, Any] = {}
|
|
180
|
+
for ph in layout.placeholders:
|
|
181
|
+
placeholders[ph.logical_name] = _placeholder_summary(ph)
|
|
182
|
+
section["placeholders"] = placeholders
|
|
183
|
+
return section
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def _example_slide(layout: LayoutContract) -> dict[str, Any]:
|
|
187
|
+
"""Generate an example slide entry using real placeholder names."""
|
|
188
|
+
content: dict[str, str] = {}
|
|
189
|
+
for ph in layout.placeholders:
|
|
190
|
+
if "image" in ph.supported_content_types and "text" not in ph.supported_content_types:
|
|
191
|
+
content[ph.logical_name] = "{ kind: image, path: path/to/image.png }"
|
|
192
|
+
else:
|
|
193
|
+
content[ph.logical_name] = f"<{ph.logical_name} text>"
|
|
194
|
+
slide: dict[str, Any] = {"layout": layout.id, "content": content}
|
|
195
|
+
return slide
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _build_template_section(manifest: ManifestDocument) -> str:
|
|
199
|
+
"""Return the template-specific portion of the reference doc."""
|
|
200
|
+
layouts_ref: dict[str, Any] = {}
|
|
201
|
+
examples: list[dict[str, Any]] = []
|
|
202
|
+
|
|
203
|
+
for layout in manifest.layouts:
|
|
204
|
+
layouts_ref[layout.id] = _layout_section(layout)
|
|
205
|
+
examples.append(_example_slide(layout))
|
|
206
|
+
|
|
207
|
+
doc: dict[str, Any] = {
|
|
208
|
+
"template": manifest.template.name,
|
|
209
|
+
"layouts": layouts_ref,
|
|
210
|
+
"example_slides": examples,
|
|
211
|
+
}
|
|
212
|
+
return yaml.safe_dump(doc, sort_keys=False, allow_unicode=True, width=120)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
# ---------------------------------------------------------------------------
|
|
216
|
+
# Public API
|
|
217
|
+
# ---------------------------------------------------------------------------
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def build_schema_document(template_dir: Path | None = None) -> str:
|
|
221
|
+
"""Return the full reference document as a string."""
|
|
222
|
+
parts = [_GENERIC_SCHEMA]
|
|
223
|
+
if template_dir is not None:
|
|
224
|
+
manifest = load_effective_manifest(template_dir)
|
|
225
|
+
parts.append("\n# ── Template-specific layouts ──────────────────────────────────\n")
|
|
226
|
+
parts.append(_build_template_section(manifest))
|
|
227
|
+
return "\n".join(parts)
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from unittest.mock import patch
|
|
4
|
+
|
|
5
|
+
from typer.testing import CliRunner
|
|
6
|
+
|
|
7
|
+
from pptx_cli.cli import app
|
|
8
|
+
from pptx_cli.commands.schema import build_schema_document
|
|
9
|
+
|
|
10
|
+
runner = CliRunner()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_generic_schema_contains_deck_structure() -> None:
|
|
14
|
+
text = build_schema_document()
|
|
15
|
+
assert "<slide-schema>" in text
|
|
16
|
+
assert "metadata:" in text
|
|
17
|
+
assert "slides:" in text
|
|
18
|
+
assert "title:" in text
|
|
19
|
+
assert "body:" in text
|
|
20
|
+
assert "notes:" in text
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_generic_schema_documents_content_types() -> None:
|
|
24
|
+
text = build_schema_document()
|
|
25
|
+
assert "kind: image" in text
|
|
26
|
+
assert "kind: table" in text
|
|
27
|
+
assert "kind: chart" in text
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_generic_schema_uses_xml_sections() -> None:
|
|
31
|
+
text = build_schema_document()
|
|
32
|
+
assert "<slide-schema>" in text
|
|
33
|
+
assert "</slide-schema>" in text
|
|
34
|
+
assert "<content-rules>" in text
|
|
35
|
+
assert "</content-rules>" in text
|
|
36
|
+
assert "<style-guide>" in text
|
|
37
|
+
assert "</style-guide>" in text
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_generic_schema_omits_layout() -> None:
|
|
41
|
+
text = build_schema_document()
|
|
42
|
+
assert "Do NOT include" in text
|
|
43
|
+
assert "layout is assigned later" in text
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_schema_command_outputs_text(tmp_path: str) -> None:
|
|
47
|
+
result = runner.invoke(app, ["schema", "--no-copy"])
|
|
48
|
+
assert result.exit_code == 0
|
|
49
|
+
assert "metadata:" in result.stdout
|
|
50
|
+
assert "slides:" in result.stdout
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def test_schema_command_copies_to_clipboard() -> None:
|
|
54
|
+
with patch("pptx_cli.cli.copy_to_clipboard", return_value=True) as mock_copy:
|
|
55
|
+
result = runner.invoke(app, ["schema"])
|
|
56
|
+
assert result.exit_code == 0
|
|
57
|
+
mock_copy.assert_called_once()
|
|
58
|
+
assert "copied to clipboard" in result.stderr
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_schema_command_no_copy_skips_clipboard() -> None:
|
|
62
|
+
with patch("pptx_cli.cli.copy_to_clipboard") as mock_copy:
|
|
63
|
+
result = runner.invoke(app, ["schema", "--no-copy"])
|
|
64
|
+
assert result.exit_code == 0
|
|
65
|
+
mock_copy.assert_not_called()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_schema_with_template(template_path: str, manifest_dir: str) -> None:
|
|
69
|
+
# First init a manifest so we can point --template at it
|
|
70
|
+
init_result = runner.invoke(
|
|
71
|
+
app,
|
|
72
|
+
["init", str(template_path), "--out", str(manifest_dir), "--format", "json"],
|
|
73
|
+
)
|
|
74
|
+
assert init_result.exit_code == 0
|
|
75
|
+
|
|
76
|
+
result = runner.invoke(app, ["schema", "--template", str(manifest_dir), "--no-copy"])
|
|
77
|
+
assert result.exit_code == 0
|
|
78
|
+
assert "template:" in result.stdout
|
|
79
|
+
assert "layouts:" in result.stdout
|
|
80
|
+
assert "placeholders:" in result.stdout
|
|
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
|
{pptx_cli-1.2.6 → pptx_cli-1.3.1}/.github/skills/pptx-deck-builder/references/excal-diagrams.md
RENAMED
|
File without changes
|
{pptx_cli-1.2.6 → pptx_cli-1.3.1}/.github/skills/pptx-deck-builder/references/mckinsey-style.md
RENAMED
|
File without changes
|
{pptx_cli-1.2.6 → pptx_cli-1.3.1}/.github/skills/pptx-deck-builder/references/pptx-workflow.md
RENAMED
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|