-
Notifications
You must be signed in to change notification settings - Fork 4
feat(library <-> taxonomy check) #214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
b3ee369
e089664
32a3747
9f9494e
62ae1d0
d5f866f
1c9dc49
39bdb5c
3641c55
1c491eb
af92292
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -2,6 +2,14 @@ | |||||
|
|
||||||
| All notable changes to GemsPy are documented here. | ||||||
|
|
||||||
| ## [Unreleased] | ||||||
|
|
||||||
| ### Added | ||||||
|
|
||||||
| - **System components: `properties`** - introduces optional `properties` on components in `system.yml` (a list of `id`/`value` pairs). These are normalized into a `dict[str, str]` on the resolved `Component` (duplicate ids raise a `ValueError`). | ||||||
| - **Model schema: `taxonomy-category`** - introduces optional `taxonomy-category` on models in library YAML files, exposed as `ModelSchema.taxonomy_category`. | ||||||
| - **Taxonomy check** - new `gems.model.taxonomy` module with `load_taxonomy(path)` and `check_library_against_taxonomy(library, taxonomy)`. Validates that every model declaring a `taxonomy-category` references a category that exists in the taxonomy file, and exposes all port IDs required by that category. Taxonomy classes (`TaxonomyItem`, `TaxonomyCategory`, `Taxonomy`) mirror the structure defined in GEMS-ViewsBuilder. | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| ## [0.1.0] - 2026-04-30 | ||||||
|
|
||||||
| ### Study folder structure | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -39,6 +39,28 @@ from `input/data-series/modeler-scenariobuilder.dat` (if present). | |||||
| Use the lower-level functions when you want to load files individually or build | ||||||
| parts of the study from in-memory data. | ||||||
|
|
||||||
| --- | ||||||
|
|
||||||
| ## System YAML: optional component `properties` | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should the model declare the list of possible properties ? |
||||||
|
|
||||||
| In `system.yml`, each component may define an optional `properties` section as a | ||||||
| list of id/value pairs: | ||||||
|
|
||||||
| ~~~ yaml | ||||||
| system: | ||||||
| components: | ||||||
| - id: nuclear_1 | ||||||
| model: basic.generator | ||||||
| properties: | ||||||
| - id: technology | ||||||
| value: nuclear | ||||||
| - id: company | ||||||
| value: rhonepower | ||||||
| ~~~ | ||||||
|
|
||||||
| At resolution time (`resolve_system` / `load_study`), this list is normalized into | ||||||
| a `dict[str, str]` stored on the resolved `Component`. Duplicate ids are rejected. | ||||||
|
Comment on lines
+61
to
+62
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need these technical details here ? Only mentioning that duplicated ids are forbidden is sufficient ? |
||||||
|
|
||||||
| ### Loading the library and the system | ||||||
|
|
||||||
| ~~~ python | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,91 @@ | ||||||
| # Copyright (c) 2026, RTE (https://www.rte-france.com) | ||||||
| # | ||||||
| # See AUTHORS.txt | ||||||
| # | ||||||
| # This Source Code Form is subject to the terms of the Mozilla Public | ||||||
| # License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
| # file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
| # | ||||||
| # SPDX-License-Identifier: MPL-2.0 | ||||||
| # | ||||||
| # This file is part of the Antares project. | ||||||
|
|
||||||
| from dataclasses import dataclass, field | ||||||
| from pathlib import Path | ||||||
| from typing import Dict, List, Optional | ||||||
|
|
||||||
| import yaml | ||||||
| from pydantic import Field | ||||||
|
|
||||||
| from gems.model.parsing import LibrarySchema | ||||||
| from gems.utils import ModifiedBaseModel | ||||||
|
|
||||||
|
|
||||||
| class TaxonomyItem(ModifiedBaseModel): | ||||||
| id: str | ||||||
|
|
||||||
|
|
||||||
| class TaxonomyCategory(ModifiedBaseModel): | ||||||
| id: str | ||||||
| parent_category: Optional[str] = None | ||||||
| variables: List[TaxonomyItem] = Field(default_factory=list) | ||||||
| parameters: List[TaxonomyItem] = Field(default_factory=list) | ||||||
| ports: List[TaxonomyItem] = Field(default_factory=list) | ||||||
| constraints: List[TaxonomyItem] = Field(default_factory=list) | ||||||
| extra_outputs: List[TaxonomyItem] = Field(default_factory=list) | ||||||
| properties: List[TaxonomyItem] = Field(default_factory=list) | ||||||
|
|
||||||
|
|
||||||
| class TaxonomyData(ModifiedBaseModel): | ||||||
| id: str | ||||||
| description: str = "" | ||||||
| categories: List[TaxonomyCategory] = Field(default_factory=list) | ||||||
|
|
||||||
|
|
||||||
| @dataclass | ||||||
| class Taxonomy: | ||||||
| id: str | ||||||
| description: str = "" | ||||||
| categories: List[TaxonomyCategory] = field(default_factory=list) | ||||||
|
|
||||||
|
|
||||||
| def load_taxonomy(taxonomy_file: Path) -> Taxonomy: | ||||||
| with open(taxonomy_file, encoding="utf-8") as f: | ||||||
| raw = yaml.safe_load(f) | ||||||
| if "taxonomy" not in raw: | ||||||
| raise ValueError(f"Missing 'taxonomy' key at root of {taxonomy_file}") | ||||||
| data = TaxonomyData.model_validate(raw["taxonomy"]) | ||||||
| return Taxonomy( | ||||||
| id=data.id, description=data.description, categories=data.categories | ||||||
| ) | ||||||
|
|
||||||
|
|
||||||
| def check_library_against_taxonomy(library: LibrarySchema, taxonomy: Taxonomy) -> None: | ||||||
| """ | ||||||
| Validates that every model declaring a taxonomy_category: | ||||||
| 1. References a category that exists in the taxonomy. | ||||||
| 2. Exposes all port IDs listed in that taxonomy category. | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| Raises ValueError describing the first violation found. | ||||||
| """ | ||||||
| categories: Dict[str, TaxonomyCategory] = {c.id: c for c in taxonomy.categories} | ||||||
|
|
||||||
| for model_schema in library.models: | ||||||
| cat_id = model_schema.taxonomy_category | ||||||
| if cat_id is None: | ||||||
| continue | ||||||
|
|
||||||
| if cat_id not in categories: | ||||||
| raise ValueError( | ||||||
| f"Model '{model_schema.id}' references taxonomy category '{cat_id}' " | ||||||
| f"which does not exist in taxonomy '{taxonomy.id}'." | ||||||
| ) | ||||||
|
|
||||||
| category = categories[cat_id] | ||||||
| model_port_ids = {p.id for p in model_schema.ports} | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You need to check more than just the ports, see above comment |
||||||
| missing = sorted({item.id for item in category.ports} - model_port_ids) | ||||||
| if missing: | ||||||
| raise ValueError( | ||||||
| f"Model '{model_schema.id}' (taxonomy-category: '{cat_id}') is missing " | ||||||
| f"port(s) required by the taxonomy: {missing}." | ||||||
| ) | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the last sentence is relevant as we do not want to mention GEMSViewsBuilder within GemsPy