Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions src/specify_cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2964,7 +2964,7 @@ def preset_catalog_add(
# Load existing config
if config_path.exists():
try:
config = yaml.safe_load(config_path.read_text()) or {}
config = yaml.safe_load(config_path.read_text(encoding="utf-8")) or {}
except Exception as e:
console.print(f"[red]Error:[/red] Failed to read {config_path}: {e}")
raise typer.Exit(1)
Expand Down Expand Up @@ -2992,7 +2992,7 @@ def preset_catalog_add(
})

config["catalogs"] = catalogs
config_path.write_text(yaml.dump(config, default_flow_style=False, sort_keys=False))
config_path.write_text(yaml.dump(config, default_flow_style=False, sort_keys=False, allow_unicode=True), encoding="utf-8")

install_label = "install allowed" if install_allowed else "discovery only"
console.print(f"\n[green]✓[/green] Added catalog '[bold]{name}[/bold]' ({install_label})")
Expand Down Expand Up @@ -3020,7 +3020,7 @@ def preset_catalog_remove(
raise typer.Exit(1)

try:
config = yaml.safe_load(config_path.read_text()) or {}
config = yaml.safe_load(config_path.read_text(encoding="utf-8")) or {}
except Exception:
console.print("[red]Error:[/red] Failed to read preset catalog config.")
raise typer.Exit(1)
Expand All @@ -3037,7 +3037,7 @@ def preset_catalog_remove(
raise typer.Exit(1)

config["catalogs"] = catalogs
config_path.write_text(yaml.dump(config, default_flow_style=False, sort_keys=False))
config_path.write_text(yaml.dump(config, default_flow_style=False, sort_keys=False, allow_unicode=True), encoding="utf-8")

console.print(f"[green]✓[/green] Removed catalog '{name}'")
if not catalogs:
Expand Down Expand Up @@ -3306,7 +3306,7 @@ def catalog_add(
# Load existing config
if config_path.exists():
try:
config = yaml.safe_load(config_path.read_text()) or {}
config = yaml.safe_load(config_path.read_text(encoding="utf-8")) or {}
except Exception as e:
console.print(f"[red]Error:[/red] Failed to read {config_path}: {e}")
raise typer.Exit(1)
Expand Down Expand Up @@ -3334,7 +3334,7 @@ def catalog_add(
})

config["catalogs"] = catalogs
config_path.write_text(yaml.dump(config, default_flow_style=False, sort_keys=False))
config_path.write_text(yaml.dump(config, default_flow_style=False, sort_keys=False, allow_unicode=True), encoding="utf-8")

install_label = "install allowed" if install_allowed else "discovery only"
console.print(f"\n[green]✓[/green] Added catalog '[bold]{name}[/bold]' ({install_label})")
Expand Down Expand Up @@ -3362,7 +3362,7 @@ def catalog_remove(
raise typer.Exit(1)

try:
config = yaml.safe_load(config_path.read_text()) or {}
config = yaml.safe_load(config_path.read_text(encoding="utf-8")) or {}
except Exception:
console.print("[red]Error:[/red] Failed to read catalog config.")
raise typer.Exit(1)
Expand All @@ -3379,7 +3379,7 @@ def catalog_remove(
raise typer.Exit(1)

config["catalogs"] = catalogs
config_path.write_text(yaml.dump(config, default_flow_style=False, sort_keys=False))
config_path.write_text(yaml.dump(config, default_flow_style=False, sort_keys=False, allow_unicode=True), encoding="utf-8")

console.print(f"[green]✓[/green] Removed catalog '{name}'")
if not catalogs:
Expand Down
2 changes: 1 addition & 1 deletion src/specify_cli/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ def render_frontmatter(fm: dict) -> str:
if not fm:
return ""

yaml_str = yaml.dump(fm, default_flow_style=False, sort_keys=False)
yaml_str = yaml.dump(fm, default_flow_style=False, sort_keys=False, allow_unicode=True)
return f"---\n{yaml_str}---\n"

def _adjust_script_paths(self, frontmatter: dict) -> dict:
Expand Down
15 changes: 8 additions & 7 deletions src/specify_cli/extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -975,8 +975,8 @@ def _load_catalog_config(self, config_path: Path) -> Optional[List[CatalogEntry]
if not config_path.exists():
return None
try:
data = yaml.safe_load(config_path.read_text()) or {}
except (yaml.YAMLError, OSError) as e:
data = yaml.safe_load(config_path.read_text(encoding="utf-8")) or {}
except (yaml.YAMLError, OSError, UnicodeError) as e:
raise ValidationError(
f"Failed to read catalog config {config_path}: {e}"
)
Expand Down Expand Up @@ -1467,8 +1467,8 @@ def _load_yaml_config(self, file_path: Path) -> Dict[str, Any]:
return {}

try:
return yaml.safe_load(file_path.read_text()) or {}
except (yaml.YAMLError, OSError):
return yaml.safe_load(file_path.read_text(encoding="utf-8")) or {}
except (yaml.YAMLError, OSError, UnicodeError):
return {}

def _get_extension_defaults(self) -> Dict[str, Any]:
Expand Down Expand Up @@ -1659,8 +1659,8 @@ def get_project_config(self) -> Dict[str, Any]:
}

try:
return yaml.safe_load(self.config_file.read_text()) or {}
except (yaml.YAMLError, OSError):
return yaml.safe_load(self.config_file.read_text(encoding="utf-8")) or {}
except (yaml.YAMLError, OSError, UnicodeError):
return {
"installed": [],
"settings": {"auto_execute_hooks": True},
Expand All @@ -1675,7 +1675,8 @@ def save_project_config(self, config: Dict[str, Any]):
"""
self.config_file.parent.mkdir(parents=True, exist_ok=True)
self.config_file.write_text(
yaml.dump(config, default_flow_style=False, sort_keys=False)
yaml.dump(config, default_flow_style=False, sort_keys=False, allow_unicode=True),
encoding="utf-8",
)

def register_hooks(self, manifest: ExtensionManifest):
Expand Down
4 changes: 2 additions & 2 deletions src/specify_cli/presets.py
Original file line number Diff line number Diff line change
Expand Up @@ -1062,8 +1062,8 @@ def _load_catalog_config(self, config_path: Path) -> Optional[List[PresetCatalog
if not config_path.exists():
return None
try:
data = yaml.safe_load(config_path.read_text()) or {}
except (yaml.YAMLError, OSError) as e:
data = yaml.safe_load(config_path.read_text(encoding="utf-8")) or {}
except (yaml.YAMLError, OSError, UnicodeError) as e:
raise PresetValidationError(
f"Failed to read catalog config {config_path}: {e}"
)
Expand Down
12 changes: 12 additions & 0 deletions tests/test_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,18 @@ def test_render_frontmatter(self):
assert output.endswith("---\n")
assert "description: Test command" in output

def test_render_frontmatter_unicode(self):
"""Test rendering frontmatter preserves non-ASCII characters."""
frontmatter = {
"description": "Prüfe Konformität der Implementierung"
}

registrar = CommandRegistrar()
output = registrar.render_frontmatter(frontmatter)

assert "Prüfe Konformität" in output
assert "\\u" not in output

def test_register_commands_for_claude(self, extension_dir, project_dir):
"""Test registering commands for Claude agent."""
# Create .claude directory
Expand Down
Loading