This guide helps you migrate from yamldataclassconfig version 1.x to 2.x. Version 2.0 introduces several breaking changes to improve type safety, code organization, and developer experience based on extensive refactoring and modern Python features.
- New factory method:
Config.create()replaces direct instantiation for better initialization - File path configuration:
create_file_path_fieldusage pattern changed significantly - Type safety improvements: Required fields no longer use nullable defaults (
= None) - API improvements: Keyword-only arguments for better API clarity (
path_is_absolute=True) - Code formatting: Standardized on double quotes and modern Python formatting
- Modern Python Features: Leverages Python 3.10+ union syntax and type hints
- Enhanced validation: Comprehensive YAML validation with
ExceptionGroupfor multiple errors - Better Type Safety: Full mypy compliance with strict mode enabled
- Runtime Type Checking: Proper handling of type annotations at runtime
pip install yamldataclassconfig>=2.0.0from myproduct.config import Config
CONFIG: Config = Config()After (v2.x):
from myproduct.config import Config
CONFIG: Config = Config.create()Why this change?
The create() factory method provides better handling of required fields and validates the config structure at instantiation time.
from pathlib import Path
from yamldataclassconfig import create_file_path_field
@dataclass
class Config(YamlDataClassConfig):
some_property: str = None
FILE_PATH: Path = create_file_path_field(Path(__file__).parent / 'config.yml')After (v2.x):
from dataclasses import dataclass
from dataclasses import field
from pathlib import Path
from yamldataclassconfig import build_path
from yamldataclassconfig.config import YamlDataClassConfig
@dataclass
class Config(YamlDataClassConfig):
some_property: str
FILE_PATH: str = field(
init=False,
default=build_path(Path(__file__).parent / "config.yml"),
)Key changes:
create_file_path_field()→build_path()with explicitfield()wrapperFILE_PATHtype changed fromPath→str
Before (v1.x):
@dataclass
class Config(YamlDataClassConfig):
property_a: int = None
property_b: str = None
part_config: PartConfig = field(
default=None,
metadata={'dataclasses_json': {'mm_field': PartConfig}}
)After (v2.x):
@dataclass
class Config(YamlDataClassConfig):
property_a: int
property_b: str
part_config: PartConfig = field(
metadata={"dataclasses_json": {"mm_field": PartConfig}},
)Benefits:
- Required fields are truly required (no more
= None) - Better type safety and IDE support
- Runtime validation ensures all required fields are present
CONFIG.load(path, True) # Positional argument
build_path(path, True) # Positional argumentAfter (v2.x):
CONFIG.load(path, path_is_absolute=True) # Keyword argument
build_path(path, path_is_absolute=True) # Keyword argumentBefore (v1.x):
try:
CONFIG.load()
except Exception as e:
print(f"Config error: {e}")After (v2.x):
If you are using Python < 3.11, install exceptiongroup:
pip install exceptiongroupimport sys
# Reason: ExceptionGroup is only available in Python 3.11+.
if sys.version_info < (3, 11): # pragma nocover
# pylint: disable-next=import-error,redefined-builtin
from exceptiongroup import ExceptionGroup # type: ignore[import-not-found]
try:
CONFIG.load()
except ExceptionGroup as eg:
print("Configuration validation failed:")
for error in eg.exceptions:
print(f" - {error}")
except Exception as e:
print(f"Config error: {e}")- Minimum Python version: 3.7+ (unchanged)
- Recommended Python version: 3.10+ for best modern union syntax support
dataclasses-json: No version change requiredPyYAML: No version change requiredmarshmallow: No version change requiredexceptiongroup: Automatically installed for Python < 3.11
Problem: Direct instantiation fails due to required fields
CONFIG = Config() # ❌ Fails in v2.xSolution: Use the factory method
CONFIG = Config.create() # ✅ Works in v2.xProblem: Function still exists but some linting tools warns
FILE_PATH: Path = create_file_path_field(Path(__file__).parent / 'config.yml') # ❌ Old patternSolution: Use new pattern with build_path and explicit field()
FILE_PATH: str = field(
init=False,
default=build_path(Path(__file__).parent / "config.yml"),
) # ✅ New patternProblem: Positional argument used for keyword-only parameter
CONFIG.load(path, True) # ❌ Positional argumentSolution: Use keyword argument
CONFIG.load(path, path_is_absolute=True) # ✅ Keyword argumentProblem: Direct access to potentially None values
print(CONFIG.part_config.property_c) # ❌ May be NoneSolution: Add null checks
if CONFIG.part_config is not None:
print(CONFIG.part_config.property_c) # ✅ Safe accessProblem: Accessing properties before calling load()
config = Config.create()
print(config.property_a) # ❌ ConfigNotLoadedErrorSolution: Always load before accessing
config = Config.create()
config.load()
print(config.property_a) # ✅ Works- Better Type Safety: Non-nullable required fields prevent runtime errors
- Enhanced Validation:
ExceptionGroupshows all validation errors at once - Modern Python Features: Support for Python 3.10+ union syntax and type hints
- Improved Code Quality: Standardized formatting and import organization
- Better API Design: Keyword-only arguments prevent parameter mistakes
- Enhanced Developer Experience: Better IDE support and type checking
- Cleaner Architecture: Separated validation logic for better maintainability
If you encounter issues, you can rollback to v1.x:
pip install "yamldataclassconfig<2.0.0"Then revert the code changes mentioned in this guide.
If you encounter issues during migration:
- Check the GitHub Issues
- Review the API documentation
- Create a new issue with your migration problem