Skip to content

Commit

Permalink
Merge pull request #16 from bis-med-it/improve_mappings
Browse files Browse the repository at this point in the history
Improve mapping modules
  • Loading branch information
sosna committed Feb 8, 2024
2 parents 8ab3348 + 6cbcfc7 commit 96e4abc
Show file tree
Hide file tree
Showing 20 changed files with 791 additions and 46 deletions.
7 changes: 4 additions & 3 deletions src/pysdmx/fmr/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@
DataflowInfo,
Hierarchy,
MetadataReport,
MultiRepresentationMap,
Organisation,
RepresentationMap,
Schema,
StructureMap,
ValueMap,
)


Expand Down Expand Up @@ -476,7 +477,7 @@ def get_mapping(

def get_code_map(
self, agency: str, id: str, version: str = "+"
) -> Sequence[ValueMap]:
) -> Union[MultiRepresentationMap, RepresentationMap]:
"""Get a code map (aka representation map).
Args:
Expand Down Expand Up @@ -811,7 +812,7 @@ async def get_mapping(

async def get_code_map(
self, agency: str, id: str, version: str = "+"
) -> Sequence[ValueMap]:
) -> Union[MultiRepresentationMap, RepresentationMap]:
"""Get a code map (aka representation map).
Args:
Expand Down
44 changes: 38 additions & 6 deletions src/pysdmx/fmr/fusion/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@
from pysdmx.fmr.fusion.core import FusionString
from pysdmx.model import (
ComponentMap,
DataType,
DatePatternMap,
FixedValueMap,
ImplicitComponentMap,
MultiComponentMap,
MultiRepresentationMap,
MultiValueMap,
RepresentationMap,
StructureMap as SM,
ValueMap,
)
Expand Down Expand Up @@ -73,16 +76,43 @@ class FusionRepresentationMap(
"""Fusion-JSON payload for a representation map."""

id: str
names: Sequence[FusionString]
agency: str
version: str
sources: Sequence[str]
targets: Sequence[str]
mappedRelationships: Sequence[FusionRepresentationMapping]
descriptions: Sequence[FusionString] = ()

def to_model(
self,
is_multi: bool = False,
) -> Sequence[Union[MultiValueMap, ValueMap]]:
"""Returns the requested value maps."""
return [rm.to_model(is_multi) for rm in self.mappedRelationships]
self, is_multi: bool = False
) -> Union[MultiRepresentationMap, RepresentationMap]:
"""Returns the requested representation map."""
mrs = [rm.to_model(is_multi) for rm in self.mappedRelationships]
s = [i if i.startswith("urn:") else DataType(i) for i in self.sources]
t = [j if j.startswith("urn:") else DataType(j) for j in self.targets]
if is_multi:
return MultiRepresentationMap(
self.id,
self.names[0].value,
self.agency,
s,
t,
mrs, # type: ignore[arg-type]
self.descriptions[0].value if self.descriptions else None,
self.version,
)
else:
return RepresentationMap(
self.id,
self.names[0].value,
self.agency,
s[0],
t[0],
mrs, # type: ignore[arg-type]
self.descriptions[0].value if self.descriptions else None,
self.version,
)


class FusionComponentMap(Struct, frozen=True):
Expand Down Expand Up @@ -195,5 +225,7 @@ class FusionRepresentationMapMessage(Struct, frozen=True):

def to_model(self) -> SM:
"""Returns the requested mapping definition."""
out = self.RepresentationMap[0].to_model()
m = self.RepresentationMap[0]
multi = bool(len(m.sources) > 1 or len(m.targets) > 1)
out = m.to_model(multi)
return out # type: ignore[return-value]
49 changes: 45 additions & 4 deletions src/pysdmx/fmr/sdmx/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@

from datetime import datetime as dt, timezone as tz
import re
from typing import Any, Optional, Sequence, Union
from typing import Any, Dict, Optional, Sequence, Union

from msgspec import Struct

from pysdmx.model import (
ComponentMap,
DataType,
DatePatternMap,
FixedValueMap,
ImplicitComponentMap,
MultiComponentMap,
MultiRepresentationMap,
MultiValueMap,
RepresentationMap,
StructureMap,
ValueMap,
)
Expand Down Expand Up @@ -70,15 +73,51 @@ class JsonRepresentationMap(
"""SDMX-JSON payload for a representation map."""

id: str
name: str
agency: str
version: str
source: Sequence[Dict[str, str]]
target: Sequence[Dict[str, str]]
representationMappings: Sequence[JsonRepresentationMapping]
description: Optional[str] = None

def __parse_st(self, item: Dict[str, str]) -> Union[DataType, str]:
if "dataType" in item:
return DataType(item["dataType"])
elif "valuelist" in item:
return item["valuelist"]
else:
return item["codelist"]

def to_model(
self, is_multi: bool = False
) -> Sequence[Union[MultiValueMap, ValueMap]]:
) -> Union[MultiRepresentationMap, RepresentationMap]:
"""Returns the requested value maps."""
return [rm.to_model(is_multi) for rm in self.representationMappings]
mrs = [rm.to_model(is_multi) for rm in self.representationMappings]
s = [self.__parse_st(i) for i in self.source]
t = [self.__parse_st(j) for j in self.target]
if is_multi:
return MultiRepresentationMap(
self.id,
self.name,
self.agency,
s,
t,
mrs, # type: ignore[arg-type]
self.description,
self.version,
)
else:
return RepresentationMap(
self.id,
self.name,
self.agency,
s[0],
t[0],
mrs, # type: ignore[arg-type]
self.description,
self.version,
)


class JsonFixedValueMap(Struct, frozen=True):
Expand Down Expand Up @@ -224,7 +263,9 @@ class JsonRepresentationMaps(Struct, frozen=True):

def to_model(self) -> Sequence[ValueMap]:
"""Returns the requested mapping definition."""
out = self.representationMaps[0].to_model()
m = self.representationMaps[0]
multi = bool(len(m.source) > 1 or len(m.target) > 1)
out = m.to_model(multi)
return out # type: ignore[return-value]


Expand Down
4 changes: 4 additions & 0 deletions src/pysdmx/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
FixedValueMap,
ImplicitComponentMap,
MultiComponentMap,
MultiRepresentationMap,
MultiValueMap,
RepresentationMap,
StructureMap,
ValueMap,
)
Expand Down Expand Up @@ -92,8 +94,10 @@ def encoders(obj: Any) -> Any:
"MetadataAttribute",
"MetadataReport",
"MultiComponentMap",
"MultiRepresentationMap",
"MultiValueMap",
"Organisation",
"RepresentationMap",
"Role",
"Schema",
"ValueMap",
Expand Down
106 changes: 92 additions & 14 deletions src/pysdmx/model/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

from msgspec import Struct

from pysdmx.model.concept import DataType


class DatePatternMap(Struct, frozen=True, omit_defaults=True):
"""A mapping based on a date pattern.
Expand Down Expand Up @@ -166,6 +168,46 @@ class ValueMap(Struct, frozen=True, omit_defaults=True):
valid_to: Optional[datetime] = None


class MultiRepresentationMap(Struct, frozen=True, omit_defaults=True):
"""Maps one or more source codelists to one or more target codelists.
A representation map is iterable, i.e. it is possible to iterate over
the various mappings using a `for` loop.
Attributes:
id: The identifier for the representation map.
name: The representation map's name.
agency: The maintainer of the representation map.
source: The URN(s) of the source codelist(s) / valuelist(s),
or data type(s).
target: The URN(s) of the target codelist(s) / valuelist(s),
or data type(s).
maps: The various mappings in the representation map.
description: Additional descriptive information about the
representation map.
version: The version of the representation map.
"""

id: str
name: str
agency: str
source: Sequence[Union[str, DataType]]
target: Sequence[Union[str, DataType]]
maps: Sequence[MultiValueMap]
description: Optional[str] = None
version: str = "1.0"

def __iter__(
self,
) -> Iterator[MultiValueMap]:
"""Return an iterator over the different maps."""
yield from self.maps

def __len__(self) -> int:
"""Return the number of maps in the representation map."""
return len(self.maps)


class MultiComponentMap(Struct, frozen=True, omit_defaults=True):
"""Maps one or more source components to one or more target components.
Expand All @@ -185,13 +227,51 @@ class MultiComponentMap(Struct, frozen=True, omit_defaults=True):
Attributes:
source: The source component(s)
target: The target component(s)
values: The list of mapped values (one or more in the source and one
or more in the target)
values: The representation map, with the list of mapped values
(one or more in the source and one or more in the target)
"""

source: Sequence[str]
target: Sequence[str]
values: Sequence[MultiValueMap]
values: MultiRepresentationMap


class RepresentationMap(Struct, frozen=True, omit_defaults=True):
"""Maps one source codelist to a target codelist.
A representation map is iterable, i.e. it is possible to iterate over
the various mappings using a `for` loop.
Attributes:
id: The identifier for the representation map.
name: The representation map's name.
agency: The maintainer of the representation map.
source: The URN of the source codelist / valuelist or a data type.
target: The URN of the target codelist / valuelist or a data type.
maps: The various mappings in the representation map.
description: Additional descriptive information about the
representation map.
version: The version of the representation map.
"""

id: str
name: str
agency: str
source: Union[str, DataType, None]
target: Union[str, DataType, None]
maps: Sequence[ValueMap]
description: Optional[str] = None
version: str = "1.0"

def __iter__(
self,
) -> Iterator[ValueMap]:
"""Return an iterator over the different maps."""
yield from self.maps

def __len__(self) -> int:
"""Return the number of maps in the representation map."""
return len(self.maps)


class ComponentMap(Struct, frozen=True, omit_defaults=True):
Expand All @@ -209,13 +289,13 @@ class ComponentMap(Struct, frozen=True, omit_defaults=True):
Attributes:
source: The source component
target: The target component
values: The list of mapped values (one in the source and
one in the target)
values: The representation map, with the list of mapped values
(one in the source and one in the target)
"""

source: str
target: str
values: Sequence[ValueMap]
values: RepresentationMap


class StructureMap(Struct, frozen=True, omit_defaults=True):
Expand All @@ -230,17 +310,15 @@ class StructureMap(Struct, frozen=True, omit_defaults=True):
by using the component id (e.g. `map["FREQ"]`).
Attributes:
id: The identifier for the codelist (e.g. CL_FREQ).
name: The codelist name (e.g. "Frequency codelist").
agency: The maintainer of the codelist (e.g. SDMX).
id: The identifier for the structure map.
name: The name of the structure map.
agency: The maintainer of the structure map.
source: The source structure.
target: The target structure.
maps: The various mapping rules in the structure map.
description: Additional descriptive information about the codelist
(e.g. "This codelist provides a set of values indicating the
frequency of the data").
version: The codelist version (e.g. 2.0.42)
description: Additional descriptive information about the structure
map.
version: The version of the structure map (e.g. 2.0.42).
"""

id: str
Expand Down
Loading

0 comments on commit 96e4abc

Please sign in to comment.