Skip to content

Commit

Permalink
Added callable discriminator
Browse files Browse the repository at this point in the history
  • Loading branch information
JB Lovland committed Jan 23, 2024
1 parent e16f5f5 commit 8acdee1
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 4 deletions.
2 changes: 2 additions & 0 deletions boom.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# type: ignore

from __future__ import annotations

from contextlib import suppress
Expand Down
2 changes: 2 additions & 0 deletions ex.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# type: ignore

import sys

from fmu.dataio.models.meta.model import Root
Expand Down
1 change: 1 addition & 0 deletions src/fmu/dataio/models/meta/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ class WellPicksContent(Content):
FaultLinesContent,
FieldOutlineContent,
FieldRegionContent,
FluidContactContent,
InplaceVolumesContent,
KPProductContent,
LiftCurvesContent,
Expand Down
45 changes: 45 additions & 0 deletions src/fmu/dataio/models/meta/discriminator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from __future__ import annotations

from typing import Literal

from pydantic import ValidationError


def fmu_discriminator(
value: dict,
) -> Literal[
"FMUAggregation",
"FMURealization",
"FMUCase",
]:
"""
Discriminate the type of FMU based on the fields present in the value.
This function determines the type of an FMU object by checking the presence
of specific fields ('aggregation' and 'realization') in the given value.
It returns a string literal indicating the determined type of the FMU.
- If both 'aggregation' and 'realization' fields are present,
it raises a ValidationError.
- If 'aggregation' is present, it returns 'FMUAggregation'.
- If 'realization' is present, it returns 'FMURealization'.
- If neither is present, it defaults to 'FMUCase'.
"""

if not isinstance(value, dict):
raise ValidationError("Input value must be a dictionary.")

if "aggregation" in value and "realization" in value:
raise ValidationError(
"Value cannot have both 'aggregation' and 'realization' "
"fields. It must exclusively be either an 'FMUAggregation' "
"or an 'FMURealization'."
)

if "aggregation" in value:
return "FMUAggregation"

if "realization" in value:
return "FMURealization"

return "FMUCase"
18 changes: 15 additions & 3 deletions src/fmu/dataio/models/meta/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
from pathlib import Path
from typing import Dict, Literal, Optional, Union

from pydantic import BaseModel, Field, NaiveDatetime, RootModel
from pydantic import BaseModel, Discriminator, Field, NaiveDatetime, RootModel, Tag
from pydantic.json_schema import GenerateJsonSchema
from typing_extensions import Annotated

from . import content, enums
from . import content, discriminator, enums


class UUID(RootModel[str]):
Expand Down Expand Up @@ -396,7 +396,19 @@ class FMUDataClassMeta(ClassMeta):
alias="class",
title="Metadata class",
)
fmu: Union[FMUAggregation, FMURealization, FMUCase]

# The presence of the a feild controlls what kind of
# FMUObj it is. The fmu_discriminator will inspects
# the obj. and returns a tag that tells pydantic
# what model to use.
fmu: Annotated[
Union[
Annotated[FMUAggregation, Tag("FMUAggregation")],
Annotated[FMURealization, Tag("FMURealization")],
Annotated[FMUCase, Tag("FMUCase")],
],
Discriminator(discriminator.fmu_discriminator),
]
access: SsdlAccess
data: content.AnyContent
file: File
Expand Down
2 changes: 1 addition & 1 deletion tests/test_schema/test_schema_logic_pydantic.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import jsonschema
import pytest
from fmu.dataio._definitions import ALLOWED_CONTENTS
from fmu.dataio.models.meta2 import dump
from fmu.dataio.models.meta import dump

# pylint: disable=no-member

Expand Down

0 comments on commit 8acdee1

Please sign in to comment.