Release standalone PPT template workflow 0.5.0
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
PPT Master - Animation Config Tool
|
||||
|
||||
Create and validate optional PPTX animation and deterministic Morph sidecars.
|
||||
|
||||
Usage:
|
||||
python3 scripts/animation_config.py scaffold <project_path>
|
||||
python3 scripts/animation_config.py list-groups <project_path>
|
||||
python3 scripts/animation_config.py validate <project_path>
|
||||
|
||||
Examples:
|
||||
python3 scripts/animation_config.py scaffold projects/demo --force
|
||||
python3 scripts/animation_config.py list-groups projects/demo
|
||||
python3 scripts/animation_config.py validate projects/demo
|
||||
|
||||
Dependencies:
|
||||
None (standard library only)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
_SCRIPTS_DIR = Path(__file__).resolve().parent
|
||||
if str(_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_SCRIPTS_DIR))
|
||||
|
||||
from console_encoding import configure_utf8_stdio # noqa: E402
|
||||
from svg_to_pptx.animation_config import ( # noqa: E402
|
||||
build_group_listing,
|
||||
load_animation_config,
|
||||
validate_animation_config,
|
||||
validate_animation_config_errors,
|
||||
validate_transition_config,
|
||||
write_scaffold,
|
||||
)
|
||||
|
||||
configure_utf8_stdio()
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Create or validate PPTX motion sidecar configuration.',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
)
|
||||
subparsers = parser.add_subparsers(dest='command', required=True)
|
||||
|
||||
scaffold = subparsers.add_parser(
|
||||
'scaffold',
|
||||
help='scan svg_output/*.svg and write animations.json scaffold',
|
||||
)
|
||||
scaffold.add_argument('project_path', help='Project directory')
|
||||
scaffold.add_argument('-o', '--output', default=None, help='Output path; default: <project>/animations.json')
|
||||
scaffold.add_argument('--force', action='store_true', help='Overwrite an existing output file')
|
||||
|
||||
list_groups = subparsers.add_parser(
|
||||
'list-groups',
|
||||
help='print one compact line per slide listing animatable group ids '
|
||||
'(chrome groups excluded); use during planning to avoid reading '
|
||||
'the full scaffold file',
|
||||
)
|
||||
list_groups.add_argument('project_path', help='Project directory')
|
||||
|
||||
validate = subparsers.add_parser(
|
||||
'validate',
|
||||
help='validate animations.json values and project-local references',
|
||||
)
|
||||
validate.add_argument('project_path', help='Project directory')
|
||||
validate.add_argument('-c', '--config', default=None, help='Config path; default: <project>/animations.json')
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = build_parser()
|
||||
args = parser.parse_args(argv)
|
||||
project_path = Path(args.project_path)
|
||||
if not project_path.exists():
|
||||
print(f'Error: Project path does not exist: {project_path}', file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if args.command == 'scaffold':
|
||||
try:
|
||||
output_path = write_scaffold(
|
||||
project_path,
|
||||
output_path=args.output,
|
||||
force=args.force,
|
||||
)
|
||||
except (FileExistsError, ValueError) as exc:
|
||||
print(f'Error: {exc}', file=sys.stderr)
|
||||
if isinstance(exc, FileExistsError):
|
||||
print('Use --force to overwrite.', file=sys.stderr)
|
||||
return 1
|
||||
print(f'Animation config scaffold written: {output_path}')
|
||||
return 0
|
||||
|
||||
if args.command == 'list-groups':
|
||||
try:
|
||||
lines, anonymous = build_group_listing(project_path)
|
||||
except ValueError as exc:
|
||||
print(f'Error: {exc}', file=sys.stderr)
|
||||
return 1
|
||||
for line in lines:
|
||||
print(line)
|
||||
for warning in anonymous:
|
||||
print(f'Warning: {warning}', file=sys.stderr)
|
||||
return 0
|
||||
|
||||
if args.command == 'validate':
|
||||
try:
|
||||
config = load_animation_config(project_path, args.config)
|
||||
except Exception as exc:
|
||||
print(f'Error: {exc}', file=sys.stderr)
|
||||
return 1
|
||||
if config is None:
|
||||
print('No animations.json found; default animation policy will be used.')
|
||||
return 0
|
||||
errors = list(dict.fromkeys(
|
||||
validate_transition_config(config)
|
||||
+ validate_animation_config_errors(config)
|
||||
))
|
||||
if errors:
|
||||
for error in errors:
|
||||
print(f'Error: {error}', file=sys.stderr)
|
||||
return 1
|
||||
reference_messages = validate_animation_config(project_path, config)
|
||||
reference_warnings = [
|
||||
message for message in reference_messages
|
||||
if ' has no id and cannot be customized in animations.json' in message
|
||||
]
|
||||
reference_errors = [
|
||||
message for message in reference_messages
|
||||
if message not in reference_warnings
|
||||
]
|
||||
for warning in reference_warnings:
|
||||
print(f'Warning: {warning}', file=sys.stderr)
|
||||
if reference_errors:
|
||||
for error in reference_errors:
|
||||
print(f'Error: {error}', file=sys.stderr)
|
||||
return 1
|
||||
print('Animation config validated successfully.')
|
||||
return 0
|
||||
|
||||
parser.print_help()
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user