Manifests#
Manifest parsers, format detection, and the parser registry.
Each parser handles both workspace configuration and task definitions
for its file format. The manifests/ package contains the internal
parser implementations. The package-root modules env_spec.py,
lockfile.py and export.py expose the public
plugin API.
parse_text(path, content) parses supplied text without discovering another
workspace. Malformed channel lists and dependency values raise
WorkspaceParseError. Conda dependency declarations must be strings or tables
of supported MatchSpec fields. Source-package fields such as path and git
are rejected. PyPI source declarations remain available in the parsed model.
Declare channels in [workspace] or [feature.<name>]. Environment and target
channel overrides are unsupported and raise an error.
Services accepting uploaded manifests can call
parse_text(path, content, reject_url_credentials=True) to reject embedded
authentication using the parser’s credential checks. The default is False,
preserving existing local read behavior. Parser diagnostics redact URL
credentials regardless of this option.
Manifest detection and parser registry (workspaces and tasks).
Search order (same for workspaces and tasks)#
conda.toml– conda-native manifest formatpixi.toml– pixi-native format (compatibility)pyproject.toml– pixi or conda tables embedded
The first file that exists and contains the relevant configuration wins.
- conda_workspaces.manifests.cached_task_parse(path_str: str) dict[str, Task][source]#
Parse tasks from a manifest file (cached by path string).
- conda_workspaces.manifests.cached_user_task_parse(path_str: str) dict[str, Task][source]#
Parse tasks from the user-level
tasks.toml(conda.toml format).
- conda_workspaces.manifests.detect_and_parse(source: str | Path | None = None) tuple[Path, WorkspaceConfig][source]#
Resolve source to a workspace manifest and parse it.
Returns
(manifest_path, workspace_config).
- conda_workspaces.manifests.detect_and_parse_tasks(file_path: Path | None = None, start_dir: Path | None = None, *, reject_symlinks: bool = False) tuple[Path, dict[str, Task], set[str]][source]#
Detect task files and parse them, merging user-level tasks.
Returns
(resolved_path, {task_name: Task}, user_only_names)where user_only_names is the set of task names that came from the user-level file and were not overridden by manifest tasks.Raises
NoTaskFileErrorwhen neither a manifest nor a user task file is found.
- conda_workspaces.manifests.detect_task_file(start_dir: Path | None = None, *, reject_symlinks: bool = False) Path | None[source]#
Walk up from start_dir looking for a file that contains tasks.
Returns the first match according to
_SEARCH_FILES, orNone.
- conda_workspaces.manifests.detect_workspace_file(start_dir: str | Path | None = None, *, reject_symlinks: bool = False) Path[source]#
Walk up from start_dir to find a workspace manifest.
Returns the path to the first matching file. Raises
WorkspaceNotFoundErrorif none is found.
- conda_workspaces.manifests.find_parser(path: Path) ManifestParser[source]#
Return the parser that can handle path.
Raises
WorkspaceParseErrorif no parser matches.
- conda_workspaces.manifests.user_task_file() Path | None[source]#
Return the user-level task file path, or
None.
- conda_workspaces.manifests.walk_manifests(start_dir: Path, predicate: str, *, reject_symlinks: bool = False) Path | None[source]#
Walk up from start_dir looking for a manifest matching predicate.
predicate is a method name on
ManifestParser— either"has_workspace"or"has_tasks". Returns the first matching file path, orNoneif none is found.
Abstract base class for manifest parsers (workspaces and tasks).
- class conda_workspaces.manifests.base.ManifestParser[source]#
Interface that every manifest parser must implement.
Each parser handles one file format (
conda.toml,pixi.toml, orpyproject.toml). Subclasses declare which files they can handle via filenames and a short format_alias ("conda"/"pixi"/"pyproject") that the CLI uses for--formatvalues. The registry inconda_workspaces.manifestsuses these to auto-detect the right parser and to resolve--formataliases to the parser that owns the matching filename.A single parser instance handles both workspace configuration and task definitions from the same file.
- add_task(path: Path, name: str, task: Task) None[source]#
Persist a top-level task definition into path.
- classmethod copy_manifest(source: Path, dest_dir: Path) Path[source]#
Copy the manifest at source into dest_dir; return the target path.
source may be a directory (walked via
resolve_source()) or a manifest file. RaisesFileNotFoundError,conda_workspaces.exceptions.WorkspaceNotFoundError, orconda_workspaces.exceptions.ManifestExistsErroras appropriate; callers layer their own dry-run / console policy on top.
- export(envs: Iterable[Environment]) str[source]#
Serialize envs to this parser’s manifest format.
Produces a manifest that, when written to disk and parsed by
parse(), describes the same requested dependencies, channels, and declared platforms that envs carry. EachEnvironmentis one(name, platform)pair; envs must all share the samename(conda’sCondaEnvironmentExporterhook callsmultiplatform_exportwith per-platform copies of the same logical environment).The default implementation writes top-level
[workspace],[dependencies],[pypi-dependencies], and[target.<platform>.*]tables — the shapeconda.tomlandpixi.tomlshare.PyprojectTomlParseroverrides it to nest the same content under[tool.conda]without disturbing the rest of the pyproject. Used as themultiplatform_exportcallable on the exporter plugins registered fromconda_workspaces.plugin.
- exporter_aliases: ClassVar[tuple[str, ...]] = ()#
Optional user-friendly aliases for the exporter plugin (e.g.
("conda",)forconda-toml). Empty tuple is fine.
- exporter_format: ClassVar[str] = ''#
Canonical
conda_environment_exportersplugin name. Empty disables exporter registration for that parser (seeconda_workspaces.plugin).
- filenames: ClassVar[tuple[str, ...]] = ()#
- classmethod for_exporter_format(name: str) ManifestParser | None[source]#
Return the registered parser whose
exporter_formatmatches name.Companion to
for_format_alias()for theconda_environment_exportersplugin side:conda workspace export --format <name>uses the exporter plugin name (e.g.pyproject-toml), which is stored onexporter_formatrather thanformat_alias. ReturnsNonewhen name is not a manifest-format exporter — the CLI uses this to decide whether to route writes throughmerge_export(), and aNoneresult simply means “not one of ours, write verbatim”.
- classmethod for_format_alias(alias: str) ManifestParser[source]#
Return the registered parser whose
format_aliasmatches alias.Used by
conda workspace init/quickstartto turn a--formatvalue like"pyproject"/"conda"/"pixi"into the parser (and therefore the filename) it implies. RaisesValueErrorwhen no parser claims alias. The companion lookup forconda workspace export --formatisfor_exporter_format()— that side matches the longerconda_environment_exportersplugin name ("pyproject-toml","conda-toml","pixi-toml") which is stored onexporter_format. The registry isconda_workspaces.manifests._PARSERS.
- format_alias: ClassVar[str] = ''#
- abstractmethod has_workspace(path: Path) bool[source]#
Return True if path contains workspace configuration.
- classmethod load_toml(path: Path) tomlkit.TOMLDocument[source]#
Read and parse one repository manifest under explicit limits.
- classmethod load_toml_with_generation(path: Path) tuple[tomlkit.TOMLDocument, FileGeneration][source]#
Read a mutable manifest and retain the generation to replace.
- classmethod manifest_data(envs: Iterable[Environment]) dict[str, Any][source]#
Fold one or more
Environmentobjects into a manifest-shaped dict.Returns the data that
export()writers need, with the format-agnostic parts decided once:name/platforms/channelsdescribe the[workspace]table (platforms are the sorted union across envs; channels are taken from the first env — exporter callers pass the same channel list on every platform).conda_deps/pypi_depsare the intersection across envs — specs that match by name and value on every platform, the ones a round-trip parse would put under the top-level[dependencies]/[pypi-dependencies]tables.target[<platform>]["conda"|"pypi"]holds the per-platform delta — specs that appear on some platforms but not others, or whose value differs across platforms. A round-trip parse restores these under[target.<platform>.dependencies]/[target.<platform>.pypi-dependencies].
Used by
export()(via_emit_manifest()) and exposed as a classmethod so individual parsers and exporter plugin shims can drive the same folding logic without duplicating it.
- property manifest_filename: str#
Canonical filename this parser reads and writes.
The first entry in
filenames— e.g."conda.toml"forCondaTomlParser. Used bymanifest_path()and theconda workspace init/quickstartCLI paths so the format-to-filename mapping lives in exactly one place.
- manifest_path(root: Path) Path[source]#
Return the manifest path this parser would (or did) write inside root.
- merge_export(existing_path: Path, exported: str) str[source]#
Return exported ready to write into an existing existing_path.
The default implementation returns exported unchanged —
conda.tomlandpixi.tomlare manifests we own end-to-end, so regenerating them from an environment is a full replacement (same asconda export -f environment.yamloverwriting an existing environment.yaml).PyprojectTomlParseroverrides this to splice the exporter’s[tool.conda]subtree into the existingpyproject.tomldocument without disturbing peer tables ([project],[build-system],[tool.ruff]etc.), becausepyproject.tomlis a shared manifest owned by the Python ecosystem. Called fromconda_workspaces.cli.workspace.exportonly when--filepoints to an existing file, so a fresh export still writes the exporter output verbatim.
- merge_export_text(existing: str, exported: str) str[source]#
Merge exported with a previously captured existing generation.
- parse(path: Path) WorkspaceConfig[source]#
Parse TOML from path and return a
WorkspaceConfig.
- abstractmethod parse_data(data: dict[str, Any], path: Path) WorkspaceConfig[source]#
Parse already-loaded manifest data associated with path.
- parse_data_with_redacted_errors(data: dict[str, Any], path: Path) WorkspaceConfig[source]#
Parse manifest data without exposing credential-bearing diagnostics.
- parse_system_requirements(requirements: Mapping[str, Any]) dict[str, str][source]#
Parse Pixi-facing system requirements into conda virtual names.
Pixi exposes TOML names like
libc/macos/windows; conda virtual packages use__glibc/__osx/__win. The workspace model stores bare conda names while preserving raw__nameescape hatches for callers that already use virtual package names.
- parse_tasks(path: Path) dict[str, Task][source]#
Parse path and return a mapping of task-name to Task.
- parse_tasks_data(data: dict[str, Any]) dict[str, Task][source]#
Parse tasks from an already loaded manifest mapping.
- parse_text(path: Path, content: str, *, reject_url_credentials: bool = False) WorkspaceConfig[source]#
Parse content and bind the result to that manifest generation.
- static parse_toml_text(content: str) TOMLDocument[source]#
Parse manifest TOML text under explicit resource limits.
- classmethod parse_toml_text_with_redacted_errors(content: str, path: Path) tomlkit.TOMLDocument[source]#
Parse mutable manifest text without exposing sensitive diagnostics.
- parse_workspace_platforms(raw: Iterable[Any], path: Path) tuple[list[str], dict[str, str], dict[str, dict[str, str]]][source]#
Parse Pixi-compatible workspace platform entries.
Bare strings remain plain conda subdirs. Inline tables can add virtual package requirements and optional Pixi rich-platform names, e.g.
{ name = "linux-64-cuda", platform = "linux-64", cuda = "12" }. The returned platform list contains the declared names used by features and lockfiles;platform_subdirsrecords the concrete conda subdir each name solves against.
- static read_manifest_text(path: Path) str[source]#
Read one repository manifest under the configured byte limit.
- static read_manifest_text_with_generation(path: Path) tuple[str, FileGeneration][source]#
Read a mutable manifest without links and return its generation.
- remove_target_overrides(container: Container, name: str) None[source]#
Remove name from every
[target.<platform>.tasks]under container.
- classmethod resolve_source(source: Path) Path[source]#
Resolve source (directory or file) to a concrete manifest path.
Directories are walked via
conda_workspaces.manifests.detect_workspace_file(); files are returned as-is. RaisesFileNotFoundErrorwhen source does not exist andconda_workspaces.exceptions.WorkspaceNotFoundErrorwhen the directory contains no recognisable manifest.
- rich_platform_system_requirement_keys: ClassVar[set[str]] = {'archspec', 'cuda', 'glibc', 'libc', 'linux', 'macos', 'osx', 'win', 'windows'}#
- system_requirement_aliases: ClassVar[dict[str, str]] = {'libc': 'glibc', 'macos': 'osx', 'windows': 'win'}#
- task_to_toml_inline(task: Task) str | InlineTable[source]#
Convert a task to a TOML-serializable value (string or inline table).
- validate_no_url_credentials(data: Mapping[str, Any], path: Path, *, content: str | None = None) None[source]#
Reject sensitive URL material anywhere in manifest-owned data.
- write_workspace_stub(base_dir: Path, name: str, channels: list[str], platforms: list[str]) tuple[Path, str][source]#
Create a minimal workspace manifest under base_dir.
Writes a fresh TOML document with
[workspace]and an empty[dependencies]table atmanifest_path()and returns(path, "Created"). RaisesManifestExistsErrorif the target file is already present — subclasses that share their file with other tooling (seePyprojectTomlParser) override this method to append their configuration under a nested table instead of refusing outright, and report"Updated"when they did so.
- conda_workspaces.manifests.base.match_spec_to_toml(spec: MatchSpec) str | InlineTable[source]#
Return a lossless workspace TOML value for a conda
MatchSpec.This is a module-level function because
MatchSpecis owned by conda and the serializer is shared by parsers, importers, mutations, and exporters.
Parser for conda.toml manifests and shared TOML helpers.
The CondaTomlParser handles conda.toml — the conda-native
manifest format for both workspace configuration and task definitions.
Public helpers for parsing shared TOML workspace tables are reused by
pixi_toml.py and pyproject_toml.py.
- class conda_workspaces.manifests.toml.CondaTomlParser[source]#
Parse
conda.tomlmanifests (workspace and tasks).This is the conda-native format that mirrors pixi.toml structure but uses
[workspace]exclusively (no[project]fallback).- exporter_format = 'conda-toml'#
Canonical
conda_environment_exportersplugin name. Empty disables exporter registration for that parser (seeconda_workspaces.plugin).
- filenames = ('conda.toml',)#
- format_alias = 'conda'#
- parse_data(data: dict[str, Any], path: Path) WorkspaceConfig[source]#
Parse already-loaded conda.toml data.
- class conda_workspaces.manifests.toml.WorkspaceDependencyResolver(*, workspace_dependencies: dict[str, Any] | None = None, path: Path | None = None)[source]#
Resolve conda dependency tables with workspace inheritance.
[workspace.dependencies]is a root-level pool. Entries in regular dependency tables opt in with{ workspace = true }; after parsing, downstream code only sees concreteMatchSpecobjects.- match_spec_from_fields(name: str, fields: dict[str, Any]) MatchSpec[source]#
Construct a
MatchSpecand wrap parse errors with manifest context.
- static match_spec_to_toml(spec: MatchSpec) str | InlineTable#
Return a lossless workspace TOML value for a conda
MatchSpec.This is a module-level function because
MatchSpecis owned by conda and the serializer is shared by parsers, importers, mutations, and exporters.
- parse_dependency(name: str, spec: Any, *, allow_inheritance: bool, table_name: str) MatchSpec[source]#
Parse one dependency entry.
- parse_dependency_table(raw: dict[str, Any], *, allow_inheritance: bool = True, table_name: str = '[dependencies]') dict[str, MatchSpec][source]#
Parse a dependency table into
MatchSpecobjects.
- reject_source_fields(name: str, spec: Any, table_name: str) None[source]#
Reject source-package fields that conda dependency parsing cannot retain.
- source_spec_fields: ClassVar[set[str]] = {'branch', 'extras', 'flags', 'git', 'path', 'rev', 'subdirectory', 'tag'}#
- spec_field_aliases: ClassVar[dict[str, str]] = {'build': 'build', 'build-number': 'build_number', 'build_number': 'build_number', 'channel': 'channel', 'features': 'features', 'file-name': 'fn', 'fn': 'fn', 'license': 'license', 'license-family': 'license_family', 'license_family': 'license_family', 'md5': 'md5', 'sha256': 'sha256', 'subdir': 'subdir', 'track-features': 'track_features', 'track_features': 'track_features', 'url': 'url', 'version': 'version'}#
- spec_fields(name: str, spec: Any) dict[str, Any][source]#
Return conda
MatchSpeckeyword fields for one TOML dependency.
- toml_spec_fields: ClassVar[dict[str, str]] = {'build': 'build', 'build_number': 'build-number', 'channel': 'channel', 'features': 'features', 'fn': 'file-name', 'license': 'license', 'license_family': 'license-family', 'md5': 'md5', 'sha256': 'sha256', 'subdir': 'subdir', 'track_features': 'track-features', 'url': 'url', 'version': 'version'}#
- conda_workspaces.manifests.toml.parse_archive_config(ws: dict[str, Any]) ArchiveConfig[source]#
Parse
[workspace.archive]into an ArchiveConfig.
- conda_workspaces.manifests.toml.parse_channels(raw: list[Any]) list[Channel][source]#
Parse a channels list, handling both strings and dicts.
- conda_workspaces.manifests.toml.parse_environment(name: str, raw: Any, path: Path, resolver: WorkspaceDependencyResolver | None = None) Environment[source]#
Parse a single environment entry.
Environments can be specified as: - A list of feature names:
env = ["feat1", "feat2"]- A dict with keys:env = {features = [...]}
- conda_workspaces.manifests.toml.parse_feature(name: str, feat_data: dict[str, Any], parser: ManifestParser, resolver: WorkspaceDependencyResolver | None = None) Feature[source]#
Parse a single
[feature.<name>]table into a Feature.Shared by
PixiTomlParserandPyprojectTomlParser— the per-feature logic is identical once the data dict is resolved.
- conda_workspaces.manifests.toml.parse_features_and_envs(source: dict[str, Any], config: WorkspaceConfig, path: Path, parser: ManifestParser) None[source]#
Parse features and environments from source into config.
Adds the default feature (from top-level deps/activation/system-reqs), all named features, and all environments. Shared by
PixiTomlParserandPyprojectTomlParser.
- conda_workspaces.manifests.toml.parse_pypi_dependencies(raw: dict[str, Any]) dict[str, PyPIDependency][source]#
Parse PyPI dependency specs.
- conda_workspaces.manifests.toml.parse_target_overrides(target_data: dict[str, Any], owner: Feature | Environment, resolver: WorkspaceDependencyResolver | None = None, *, table_path: str = 'target') None[source]#
Parse target dependency overrides into a feature or environment.
- conda_workspaces.manifests.toml.tasks_to_toml(tasks: dict[str, Task]) str[source]#
Serialize a full task dict to
conda.tomlTOML string.
Parser for pixi.toml workspace manifests.
Reads [workspace] (or [project] for legacy manifests),
[dependencies], [pypi-dependencies], [feature.*],
[environments], and [target.*] tables from pixi.toml.
- class conda_workspaces.manifests.pixi_toml.PixiTomlParser[source]#
Parse
pixi.tomlmanifests (workspace and tasks).- exporter_format = 'pixi-toml'#
Canonical
conda_environment_exportersplugin name. Empty disables exporter registration for that parser (seeconda_workspaces.plugin).
- filenames = ('pixi.toml',)#
- format_alias = 'pixi'#
- parse_data(data: dict[str, Any], path: Path) WorkspaceConfig[source]#
Parse already-loaded pixi-style manifest data.
Parser for pyproject.toml workspace manifests.
Reads workspace configuration from pyproject.toml, trying these
tables in order:
[tool.conda.workspace]– conda-native table[tool.pixi.workspace]– pixi compatibility
- class conda_workspaces.manifests.pyproject_toml.PyprojectTomlParser[source]#
Parse workspace and task config from
pyproject.toml.Tries these tool tables in priority order:
[tool.conda.*]– conda-native tables[tool.pixi.*]– pixi compatibility
- add_task(path: Path, name: str, task: Task) None[source]#
Persist a top-level task definition into path.
- export(envs: Iterable[Environment]) str[source]#
Serialize envs as a
pyproject.tomlwith[tool.conda.*].Same content as
ManifestParser.export()— workspace table, dependencies, optional pypi-dependencies, optional per-platform overrides — but wrapped under[tool.conda]so the output drops straight into PEP 621 /pyproject.tomlalongside[project],[build-system], and peer tables.
- exporter_format = 'pyproject-toml'#
Canonical
conda_environment_exportersplugin name. Empty disables exporter registration for that parser (seeconda_workspaces.plugin).
- filenames = ('pyproject.toml',)#
- format_alias = 'pyproject'#
- merge_export(existing_path: Path, exported: str) str[source]#
Splice exported’s
[tool.conda]into existing_path.pyproject.tomlis a shared packaging manifest owned by the Python ecosystem; the default “overwrite the file wholesale” behaviour ofManifestParser.merge_export()would silently destroy[project]/[build-system]/[tool.ruff]/ etc. Instead we parse the existing document, replace its[tool.conda]subtree with the oneexport()just produced, and serialise the result.This is the export-side companion to
write_workspace_stub(), which does the same kind of nested-table merge forconda workspace init. Existing[tool.pixi]content is preserved untouched — users who mix both tools stay functional.
- merge_export_text(existing: str, exported: str) str[source]#
Splice an export into one already captured pyproject generation.
- parse_data(data: dict[str, Any], path: Path) WorkspaceConfig[source]#
Parse already-loaded pyproject manifest data.
- parse_tasks_data(data: dict[str, Any]) dict[str, Task][source]#
Parse embedded tasks from an already loaded manifest mapping.
- tool_section_for_tasks(doc: tomlkit.TOMLDocument) Table[source]#
Return the
toolsub-table that owns tasks.Uses the same precedence as
parse_tasks: non-emptytool.condawins, then non-emptytool.pixi, then falls back totool.condafor new manifests.
- write_workspace_stub(base_dir: Path, name: str, channels: list[str], platforms: list[str]) tuple[Path, str][source]#
Add
[tool.conda.workspace]to base_dir/pyproject.toml.Unlike the default
ManifestParser.write_workspace_stub()(which refuses to touch an existing file),pyproject.tomlis a shared packaging manifest owned by the Python ecosystem — PEP 621[project],[build-system], and other tooling tables routinely coexist with ours. We read the existing document if any, add our configuration under the nested[tool.conda]table, and report"Updated"so the CLI can distinguish an append from a create. An existing[tool.conda]or[tool.pixi]raisesManifestExistsError.
Shared logic for normalizing raw task dicts into Task model objects.
- conda_workspaces.manifests.normalize.normalize_args(raw: list[Any] | None) list[TaskArg][source]#
Convert raw arg definitions into TaskArg objects.
Accepted shapes: -
["name"](required arg, no default) -[{"arg": "name", "default": "value"}]-[{"arg": "name", "default": "value", "choices": ["a", "b"]}]
- conda_workspaces.manifests.normalize.normalize_depends_on(raw: list[Any] | str | None) list[TaskDependency][source]#
Convert the various
depends-onformats into TaskDependency objects.Accepted shapes: -
["foo", "bar"](simple list of task names) -[{"task": "foo", "args": ["x"]}, ...](full dict form) -[{"task": "foo"}, {"task": "bar"}](pixi alias shorthand)
- conda_workspaces.manifests.normalize.normalize_override(raw: dict[str, Any]) TaskOverride[source]#
Parse a raw dict into a TaskOverride.
- conda_workspaces.manifests.normalize.normalize_task(name: str, raw: str | list[Any] | dict[str, Any]) Task[source]#
Convert a single raw task value into a Task object.
Handles all the shorthand forms: -
"command string"(simple string command) -["dep1", "dep2"]or[{"task": ...}](alias / dependency-only) -{cmd: ..., depends-on: ..., ...}(full dict definition)
- conda_workspaces.manifests.normalize.parse_feature_tasks(data: dict[str, Any], tasks: dict[str, Task]) None[source]#
Parse
[feature.<name>.tasks]and their target overrides.Merges feature-scoped tasks into tasks in place. Shared by
PixiTomlParserandPyprojectTomlParser.
- conda_workspaces.manifests.normalize.parse_tasks_and_targets(data: dict[str, Any]) dict[str, Task][source]#
Parse
[tasks]and[target.<platform>.tasks]from a data dict.Shared by
CondaTomlParser,PixiTomlParser, andPyprojectTomlParser— the core parsing logic is identical across all three formats once the root data dict is resolved.