Environment Exporters#
The environment exporter plugin hook allows you to create custom export formats for conda environments. This feature was introduced to enhance the conda export command with a plugin-based architecture for extending conda's environment export capabilities.
Overview#
Environment exporters transform conda environments into various file formats that can be shared, stored, or used to recreate environments. The plugin system supports both structured formats (like YAML/JSON) and text-based formats (like explicit URLs or requirement specs).
Built-in exporters include:
Plugin Architecture#
Environment exporters are registered through the conda_environment_exporters
plugin hook.
Each exporter defines:
A unique name and optional aliases
Supported filename patterns for auto-detection
An export function that transforms environments to the target format
- class CondaEnvironmentExporter#
EXPERIMENTAL
Return type to use when defining a conda environment exporter plugin hook.
- Parameters:
name -- name of the exporter (e.g.,
environment-yaml
)aliases -- user-friendly format aliases (e.g., ("yaml",))
default_filenames -- default filenames this exporter handles (e.g., ("environment.yml", "environment.yaml"))
export -- callable that exports an Environment to string format
- aliases#
- default_filenames#
- export#
- name#
- conda_environment_exporters()#
Register new conda environment exporter
Environment exporters serialize conda Environment objects to different output formats (JSON, TOML, XML, etc.) for the 'conda export' command. This is separate from environment specifiers which parse input files.
Example:
import tomlkit from conda import plugins from conda.exceptions import CondaValueError from conda.models.environment import Environment from conda.plugins.types import CondaEnvironmentExporter def export_toml(env: Environment) -> str: # Export Environment to TOML format # For formats that use the standard dictionary structure, # you can use the shared utility: from conda.plugins.environment_exporters.standard import to_dict env_dict = to_dict(env) # Create TOML document toml_doc = tomlkit.document() if env_dict.get("name"): toml_doc["name"] = env_dict["name"] if env_dict.get("channels"): toml_doc["channels"] = env_dict["channels"] if env_dict.get("dependencies"): toml_doc["dependencies"] = env_dict["dependencies"] if env_dict.get("variables"): toml_doc["variables"] = env_dict["variables"] return tomlkit.dumps(toml_doc) @plugins.hookimpl def conda_environment_exporters(): yield CondaEnvironmentExporter( name="environment-toml", aliases=("toml",), default_filenames=("environment.toml",), export=export_toml, )
Creating an Environment Exporter Plugin#
What follows are several examples showing how to create new export formats using the environment exporters plugin hook. Please check out our Quick start guide for more detailed instructions on how to create a conda plugin.
Basic Plugin Structure#
Here's a minimal example of an environment exporter plugin:
import conda.plugins
from conda.models.environment import Environment
def export_simple_text(environment: Environment) -> str:
"""Export environment as a simple text list."""
lines = [f"# Environment: {environment.name}"]
if environment.dependencies:
lines.append("# Dependencies:")
for dep in environment.dependencies:
lines.append(str(dep))
return "\n".join(lines)
@conda.plugins.hookimpl
def conda_environment_exporters():
yield conda.plugins.CondaEnvironmentExporter(
name="simple-text",
aliases=("simple", "txt-simple"),
default_filenames=("environment.txt",),
export=export_simple_text,
)
See also
For a general introduction and examples of how to distribute conda plugins, see the ../plugins quick start guide.
Plugin Components#
Below, we explain how to use the plugin you've created above with conda export.
Name and Aliases#
The name
field defines the canonical format name used with --format
:
conda export --format=simple-text
The aliases
tuple provides alternative names for convenience:
conda export --format=simple
conda export --format=txt-simple
Note
Aliases are automatically normalized to lowercase and stripped of whitespace. The plugin system will detect and prevent name collisions.
Default Filenames#
The default_filenames
tuple specifies filename patterns for automatic format detection:
# These would auto-detect the simple-text format
conda export --file=environment.txt
Export Function#
The export function receives an Environment
object
and returns a string representation:
def export_function(environment: Environment) -> str:
# Access environment properties:
# - environment.name: environment name
# - environment.channels: configured channels
# - environment.dependencies: requested packages (MatchSpec objects)
# - environment.explicit_packages: all installed packages (PackageRecord objects)
# - environment.variables: environment variables
return "formatted content"
Advanced Example: JSON Exporter#
Here's a more sophisticated example that creates a custom JSON format:
import json
from typing import Any, Dict
import conda.plugins
from conda.models.environment import Environment
def export_custom_json(environment: Environment) -> str:
"""Export environment as custom JSON format."""
data: Dict[str, Any] = {
"format_version": "1.0",
"environment": {
"name": environment.name,
"channels": [str(channel) for channel in environment.channels],
},
}
# Add dependencies as MatchSpec strings
if environment.dependencies:
data["environment"]["dependencies"] = [
str(dep) for dep in environment.dependencies
]
# Add explicit packages with full metadata
if environment.explicit_packages:
data["environment"]["explicit_packages"] = [
{
"name": pkg.name,
"version": pkg.version,
"build": pkg.build,
"channel": str(pkg.channel),
"url": pkg.url,
"md5": pkg.md5,
}
for pkg in environment.explicit_packages
]
# Add environment variables
if environment.variables:
data["environment"]["variables"] = dict(environment.variables)
return json.dumps(data, indent=2, sort_keys=True)
@conda.plugins.hookimpl
def conda_environment_exporters():
yield conda.plugins.CondaEnvironmentExporter(
name="custom-json",
aliases=("cjson",),
default_filenames=("environment.cjson", "env.cjson"),
export=export_custom_json,
)
Error Handling#
Your export function should handle error cases appropriately:
from conda.exceptions import CondaValueError
def export_strict_format(environment: Environment) -> str:
"""Export that requires specific conditions."""
if not environment.dependencies:
raise CondaValueError(
"Cannot export strict format: no dependencies found. "
"This format requires at least one dependency."
)
if not environment.name:
raise CondaValueError(
"Cannot export strict format: environment name is required."
)
# Continue with export...
return formatted_content
Working with Different Package Types#
Understanding Package Collections#
The Environment model provides different package collections for different use cases:
dependencies
(MatchSpec
objects)Represents user-requested packages. These are the packages the user explicitly asked for, either from history (when using
--from-history
) or converted from installed packages.explicit_packages
(PackageRecord
objects)Represents all installed packages with full metadata including URLs, checksums, and build information. Used for exact reproduction.
Example usage patterns:
def export_user_requested(environment: Environment) -> str:
"""Export only what the user explicitly requested."""
if not environment.dependencies:
raise CondaValueError("No requested packages found")
lines = []
for dep in environment.dependencies:
lines.append(str(dep)) # e.g., "numpy=1.21.0"
return "\n".join(lines)
def export_exact_reproduction(environment: Environment) -> str:
"""Export for exact environment reproduction."""
if not environment.explicit_packages:
raise CondaValueError("No installed packages found")
lines = ["@EXPLICIT"]
for pkg in environment.explicit_packages:
lines.append(pkg.url) # Full package URL
return "\n".join(lines)
Plugin Detection and Conflicts#
Automatic Format Detection#
When users run conda export --file=filename.ext
, conda:
Checks all registered exporters for matching
default_filenames
If exactly one match is found, uses that exporter
If no matches or multiple matches, raises an appropriate error
The detection system is case-insensitive and supports glob-like patterns.
Collision Prevention#
The plugin system automatically prevents naming conflicts:
Format names and aliases are normalized (lowercase, stripped)
Duplicate format names or aliases raise
PluginError
This ensures deterministic behavior and clear error messages
Testing Your Plugin#
Here's a basic test structure for your exporter plugin:
import pytest
from conda.models.environment import Environment
from conda.testing.fixtures import tmp_env
from my_export_plugin.exporters import export_custom_json
def test_custom_json_exporter(tmp_env):
"""Test the custom JSON exporter."""
environment = Environment.from_prefix(tmp_env.prefix)
result = export_custom_json(environment)
# Verify the output format
import json
data = json.loads(result)
assert data["format_version"] == "1.0"
assert "environment" in data
assert "name" in data["environment"]
def test_empty_environment_handling(tmp_env):
"""Test exporter with empty environment."""
environment = Environment(name="test-empty")
# Should handle gracefully or raise appropriate error
result = export_custom_json(environment)
data = json.loads(result)
assert data["environment"]["name"] == "test-empty"
Best Practices#
Validation: Always validate inputs and provide clear error messages
Documentation: Include format specifications and examples in your plugin
Backwards compatibility: Consider versioning your format for future changes
Performance: Optimize for large environments with many packages
Cross-platform: Consider platform differences in your format design
Example Use Cases#
Some ideas for custom environment exporters:
Docker integration: Export as Dockerfile or Docker Compose
Language-specific: Export as language package files (package.json, Gemfile, etc.)
Cloud deployment: Export as cloud infrastructure templates
Version control: Export in formats optimized for VCS tracking
Documentation: Export as formatted documentation or reports
Further Reading#
For more information about conda plugin development:
Plugin overview - General plugin development guide
Environment specifiers - Input counterpart to exporters
conda.models.environment.Environment
- Environment model APIconda export - Export command documentation