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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,17 @@ If upgrading from v2.x, see the [v3.0.0 release notes](https://github.com/flixOp

Until here -->

## [4.1.3] - 2025-11-25

**Summary**: Re-add mistakenly removed method for loading a config from file

If upgrading from v2.x, see the [v3.0.0 release notes](https://github.com/flixOpt/flixOpt/releases/tag/v3.0.0) and [Migration Guide](https://flixopt.github.io/flixopt/latest/user-guide/migration-guide-v3/).

### 🐛 Fixed
- Re-added `CONFIG.load_from_file()` method that was accidentally removed

---

## [4.1.2] - 2025-11-24

**Summary**:
Expand Down
68 changes: 68 additions & 0 deletions flixopt/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,74 @@ def browser_plotting(cls) -> type[CONFIG]:

return cls

@classmethod
def load_from_file(cls, config_file: str | Path) -> type[CONFIG]:
"""Load configuration from YAML file and apply it.

Args:
config_file: Path to the YAML configuration file.

Returns:
The CONFIG class for method chaining.

Raises:
FileNotFoundError: If the config file does not exist.

Examples:
```python
CONFIG.load_from_file('my_config.yaml')
```

Example YAML file:
```yaml
config_name: my_project
modeling:
big: 10000000
epsilon: 0.00001
solving:
mip_gap: 0.001
time_limit_seconds: 600
plotting:
default_engine: matplotlib
default_dpi: 600
```
"""
# Import here to avoid circular import
from . import io as fx_io

config_path = Path(config_file)
if not config_path.exists():
raise FileNotFoundError(f'Config file not found: {config_file}')

config_dict = fx_io.load_yaml(config_path)
cls._apply_config_dict(config_dict)

return cls

@classmethod
def _apply_config_dict(cls, config_dict: dict) -> None:
"""Apply configuration dictionary to class attributes.

Args:
config_dict: Dictionary containing configuration values.
"""
for key, value in config_dict.items():
if key == 'modeling' and isinstance(value, dict):
for nested_key, nested_value in value.items():
if hasattr(cls.Modeling, nested_key):
setattr(cls.Modeling, nested_key, nested_value)
elif key == 'solving' and isinstance(value, dict):
for nested_key, nested_value in value.items():
if hasattr(cls.Solving, nested_key):
setattr(cls.Solving, nested_key, nested_value)
elif key == 'plotting' and isinstance(value, dict):
for nested_key, nested_value in value.items():
if hasattr(cls.Plotting, nested_key):
setattr(cls.Plotting, nested_key, nested_value)
elif hasattr(cls, key) and key != 'logging':
# Skip 'logging' as it requires special handling via CONFIG.Logging methods
setattr(cls, key, value)


def change_logging_level(level_name: str | int) -> None:
"""Change the logging level for the flixopt logger.
Expand Down