Source code for ptyrad.cli.templates
"""
CLI utility functions for setting up fresh project folder, and exporting templates / examples params files
"""
import shutil
import sys
from pathlib import Path
from importlib import resources
[docs]
def create_starter_project(project_name: str = "ptyrad", force: bool = False):
"""
Copies the internal 'demo' folder to a new directory named project_name.
"""
dest = Path(project_name).resolve()
# 1. Safety Check: Don't overwrite unless forced
if dest.exists():
if not force:
print(f"Error: Directory '{dest.name}' already exists.")
print(f" Use 'ptyrad init {dest.name} --force' to overwrite it.")
sys.exit(1)
else:
print(f" Overwriting existing directory: {dest}")
shutil.rmtree(dest)
# 2. Locate the internal demo folder
# We look for the package 'ptyrad.starter'
try:
source_ref = resources.files("ptyrad.starter")
except (ImportError, TypeError):
# Fallback for localized dev installs or broken packages
print("Error: Could not locate internal demo files.")
sys.exit(1)
# 3. Copy the Tree
# copytree creates the destination directory for us.
try:
with resources.as_file(source_ref) as src_path:
shutil.copytree(
src_path,
dest,
ignore=shutil.ignore_patterns("__*", "*.pyc") # Skip __init__.py and cache
)
print(f"Created starter project at: {dest}")
print( " Structure:")
print(f" ├── {dest.name}/data/ (Place your data here)")
print(f" ├── {dest.name}/notebooks/ (Workflow notebooks)")
print(f" ├── {dest.name}/output/ (Output results here)")
print(f" ├── {dest.name}/params/ (Example params files)")
print(f" └── {dest.name}/scripts/ (Example scripts)")
except Exception as e:
print(f"Failed to create project: {e}")
sys.exit(1)
def _export_resource(resource_subpath: str, dest_name: str, dest_parent: str = ".", force: bool = False, description: str = "files"):
"""
Internal helper to copy a specific subfolder from ptyrad.starter to a local destination.
Args:
resource_subpath: Path inside ptyrad.starter (e.g., "params" or "params/templates")
dest_name: Name of the folder to create locally (e.g., "params" or "templates")
dest_parent: Local directory where dest_name will be created
force: Whether to overwrite existing folders
description: Text description for print messages
"""
# 1. Setup paths
target_path = Path(dest_parent).resolve() / dest_name
# 2. Check for conflicts
if target_path.exists():
if not force:
print(f"Error: Directory '{target_path.name}' already exists at {target_path.parent}")
print(" Use --force to overwrite: -f")
sys.exit(1)
else:
print(f"Overwriting existing {dest_name} folder: {target_path}")
try:
shutil.rmtree(target_path, ignore_errors=False)
except OSError as e:
print(f"Error removing existing folder: {e}")
sys.exit(1)
# 3. Copy the resource
try:
# Access the root 'ptyrad.starter' package
demo_root = resources.files("ptyrad.starter")
# Drill down to the specific subfolder (e.g. demo/params or demo/params/templates)
# We split by '/' to handle nested paths like "params/templates" safely
source_path = demo_root
for part in resource_subpath.split("/"):
source_path = source_path.joinpath(part)
if not source_path.is_dir():
print(f"Error: Could not locate '{resource_subpath}' folder inside package.")
sys.exit(1)
# Copy files
with resources.as_file(source_path) as src_path:
shutil.copytree(src_path, target_path)
print(f"{description.capitalize()} exported to: {target_path}")
# 1. Search for both .yaml AND .yml
# rglob returns a generator, so we chain them or use a set comprehension
yaml_files = list(target_path.rglob('*.yaml'))
yml_files = list(target_path.rglob('*.yml'))
all_files = sorted(yaml_files + yml_files)
# 2. Convert to relative paths (e.g. "templates/minimal.yaml")
# This makes it obvious where files are located
file_list = [str(f.relative_to(target_path)) for f in all_files]
if file_list:
print("Files:")
for file in file_list:
print(f" {file}")
else:
print(" (No YAML files found in export)")
except Exception as e:
print(f"Failed to export {description}: {e}")
sys.exit(1)
[docs]
def export_params(dest_dir: str = ".", force: bool = False):
"""
Copies the entire 'starter/params/' folder (including templates/, examples/, walkthrough/) locally.
"""
_export_resource(
resource_subpath="params",
dest_name="params",
dest_parent=dest_dir,
force=force,
description="Parameter files"
)
[docs]
def export_templates(dest_dir: str = ".", force: bool = False):
"""
Copies only the 'starter/params/templates/' folder locally.
"""
_export_resource(
resource_subpath="params/templates",
dest_name="templates",
dest_parent=dest_dir,
force=force,
description="Clean templates"
)
[docs]
def export_examples(dest_dir: str = ".", force: bool = False):
"""
Copies only the 'starter/params/examples/' folder locally.
"""
_export_resource(
resource_subpath="params/examples",
dest_name="examples",
dest_parent=dest_dir,
force=force,
description="Explicit examples"
)
[docs]
def export_walkthrough(dest_dir: str = ".", force: bool = False):
"""
Copies only the 'starter/params/walkthrough/' folder locally.
"""
_export_resource(
resource_subpath="params/walkthrough",
dest_name="walkthrough",
dest_parent=dest_dir,
force=force,
description="Walkthrough params"
)