Source code for conda_workspaces.manifests.pixi_toml

"""Parser for pixi.toml workspace manifests.

Reads ``[workspace]`` (or ``[project]`` for legacy manifests),
``[dependencies]``, ``[pypi-dependencies]``, ``[feature.*]``,
``[environments]``, and ``[target.*]`` tables from pixi.toml.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

import tomlkit

from ..exceptions import TaskParseError, WorkspaceParseError
from ..models import WorkspaceConfig
from .base import ManifestParser
from .normalize import parse_feature_tasks, parse_tasks_and_targets
from .toml import (
    parse_archive_config,
    parse_channels,
    parse_features_and_envs,
)

if TYPE_CHECKING:
    from pathlib import Path

    from ..models import Task


[docs] class PixiTomlParser(ManifestParser): """Parse ``pixi.toml`` manifests (workspace and tasks).""" format_alias = "pixi" filenames = ("pixi.toml",) exporter_format = "pixi-toml"
[docs] def can_handle(self, path: Path) -> bool: return path.name in self.filenames
[docs] def has_workspace(self, path: Path) -> bool: data = self.read_toml(str(path)) return "workspace" in data or "project" in data
[docs] def parse(self, path: Path) -> WorkspaceConfig: try: text = path.read_text(encoding="utf-8") # ``unwrap()`` returns plain Python types; otherwise tomlkit # subclasses (e.g. ``tomlkit.items.String``) leak through the # data model and trip ruamel.yaml's exact-type key dispatch # at lockfile write time. Callers that need round-tripping # (``conda workspace add/remove/init``) still work on the raw # ``TOMLDocument`` separately. data = tomlkit.loads(text).unwrap() except Exception as exc: raise WorkspaceParseError(path, str(exc)) from exc root = str(path.parent) # workspace table (pixi v0.23+) or legacy project table ws = data.get("workspace", data.get("project", {})) if not ws: raise WorkspaceParseError(path, "No [workspace] or [project] table found") ( platforms, platform_subdirs, platform_system_requirements, ) = self.parse_workspace_platforms( ws.get("platforms", []), path, ) config = WorkspaceConfig( name=ws.get("name"), version=ws.get("version"), description=ws.get("description"), channels=parse_channels(ws.get("channels", [])), platforms=platforms, platform_subdirs=platform_subdirs, platform_system_requirements=platform_system_requirements, root=root, manifest_path=str(path), channel_priority=ws.get("channel-priority"), archive=parse_archive_config(ws), ) parse_features_and_envs(data, config, path, self) return config
[docs] def has_tasks(self, path: Path) -> bool: return bool(self.read_toml(str(path)).get("tasks"))
[docs] def parse_tasks(self, path: Path) -> dict[str, Task]: try: data = tomlkit.loads(path.read_text(encoding="utf-8")).unwrap() except Exception as exc: raise TaskParseError(str(path), str(exc)) from exc tasks = parse_tasks_and_targets(data) parse_feature_tasks(data, tasks) return tasks