Skip to content

Commit

Permalink
Merge pull request #8 from bis-med-it/structure_map
Browse files Browse the repository at this point in the history
Improve mapping module
  • Loading branch information
sosna committed Jan 8, 2024
2 parents 1552922 + 2fbb369 commit c79ae2e
Show file tree
Hide file tree
Showing 21 changed files with 706 additions and 329 deletions.
2 changes: 1 addition & 1 deletion docs/api/model/map.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ Mapping definitions
- :ref:`map`.

.. automodule:: pysdmx.model.map
:members: MappingDefinition, ComponentMapper, MultipleComponentMapper, ValueMap, MultipleValueMap, ImplicitMapper, ValueSetter, DateMapper
:members: StructureMap, ComponentMap, MultiComponentMap, ValueMap, MultiValueMap, ImplicitComponentMap, FixedValueMap, DatePatternMap
8 changes: 4 additions & 4 deletions docs/howto/map.rst
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ this is the case for ``OPTION_TYPE``, ``TO``, and ``OI``.
for m in mapping.implicit_maps:
print(m)
# Output example:
# ImplicitMapper(source='OPT_TYP', target='OPTION_TYPE')
# ImplicitComponentMap(source='OPT_TYP', target='OPTION_TYPE')
As seen, the operation to be applied is fairly simple:

Expand All @@ -151,7 +151,7 @@ Another fairly simple case is setting fixed values. This is the case for
for m in mapping.fixed_value_maps:
print(m)
# Output example:
# ValueSetter(target='FREQ', value='M')
# FixedValueMap(target='FREQ', value='M')
Mapping Codes
"""""""""""""
Expand All @@ -165,7 +165,7 @@ mappings can be retrieved via the ``component_maps`` property:
for m in mapping.component_maps:
print(m)
# Output example:
# ComponentMapper(
# ComponentMap(
# source='CONTRACT',
# target='CONTRACT',
# values=[
Expand Down Expand Up @@ -209,7 +209,7 @@ property:
for m in rm.date_maps:
print(m)
# Output example:
# DateMapper(source='ACTIVITY_DATE', target='TIME_PERIOD', pattern='MM/dd/yyyy', frequency='M')
# PatternMap(source='ACTIVITY_DATE', target='TIME_PERIOD', pattern='MM/dd/yyyy', frequency='M')
Here, we need to parse the date using the supplied pattern, ``MM/dd/yyyy``,
i.e., dates like ``12/25/2013``. Once this is done, we need to format them to
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "pysdmx"
version = "1.0.0-beta-1"
version = "1.0.0-beta-2"
description = "Your opinionated Python SDMX library"
authors = [
"Xavier Sosnovsky <xavier.sosnovsky@bis.org>",
Expand Down
2 changes: 1 addition & 1 deletion src/pysdmx/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Your opinionated Python SDMX library."""

__version__ = "1.0.0-beta-1"
__version__ = "1.0.0-beta-2"
10 changes: 5 additions & 5 deletions src/pysdmx/fmr/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
ConceptScheme,
DataflowInfo,
Hierarchy,
MappingDefinition,
MetadataReport,
Organisation,
Schema,
StructureMap,
ValueMap,
)

Expand Down Expand Up @@ -432,7 +432,7 @@ def get_mapping(
agency: str,
id: str,
version: str = "+",
) -> MappingDefinition:
) -> StructureMap:
"""Get a mapping definition (aka structure map).
Args:
Expand All @@ -450,7 +450,7 @@ def get_mapping(
def get_code_map(
self, agency: str, id: str, version: str = "+"
) -> Sequence[ValueMap]:
"""Get a mapping definition.
"""Get a code map (aka representation map).
Args:
agency: The agency maintaining the representation map.
Expand Down Expand Up @@ -741,7 +741,7 @@ async def get_mapping(
agency: str,
id: str,
version: str = "+",
) -> MappingDefinition:
) -> StructureMap:
"""Get a mapping definition (aka structure map).
Args:
Expand All @@ -759,7 +759,7 @@ async def get_mapping(
async def get_code_map(
self, agency: str, id: str, version: str = "+"
) -> Sequence[ValueMap]:
"""Get a representation map.
"""Get a code map (aka representation map).
Args:
agency: The agency maintaining the representation map.
Expand Down
88 changes: 54 additions & 34 deletions src/pysdmx/fmr/fusion/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@

from msgspec import Struct

from pysdmx.fmr.fusion.core import FusionString
from pysdmx.model import (
ComponentMapper,
DateMapper,
ImplicitMapper,
MappingDefinition,
MultipleComponentMapper,
MultipleValueMap,
ComponentMap,
DatePatternMap,
FixedValueMap,
ImplicitComponentMap,
MultiComponentMap,
MultiValueMap,
StructureMap as SM,
ValueMap,
ValueSetter,
)
from pysdmx.util import find_by_urn

Expand Down Expand Up @@ -46,10 +47,10 @@ def __get_dt(self, inp: str) -> dt:
inp = inp[0:-1]
return dt.fromisoformat(inp).replace(tzinfo=tz.utc)

def to_model(self, is_multi: bool) -> Union[MultipleValueMap, ValueMap]:
def to_model(self, is_multi: bool) -> Union[MultiValueMap, ValueMap]:
"""Returns the requested value maps."""
if is_multi:
return MultipleValueMap(
return MultiValueMap(
[src.to_model() for src in self.source],
self.target,
self.__get_dt(self.validFrom) if self.validFrom else None,
Expand Down Expand Up @@ -79,7 +80,7 @@ class FusionRepresentationMap(
def to_model(
self,
is_multi: bool = False,
) -> Sequence[Union[MultipleValueMap, ValueMap]]:
) -> Sequence[Union[MultiValueMap, ValueMap]]:
"""Returns the requested value maps."""
return [rm.to_model(is_multi) for rm in self.mappedRelationships]

Expand All @@ -93,67 +94,86 @@ class FusionComponentMap(Struct, frozen=True):

def to_model(
self, rms: Sequence[FusionRepresentationMap]
) -> Union[ComponentMapper, MultipleComponentMapper, ImplicitMapper]:
) -> Union[ComponentMap, MultiComponentMap, ImplicitComponentMap]:
"""Returns the requested component map."""
if self.representationMapRef:
rm = find_by_urn(rms, self.representationMapRef)
if len(self.sources) == 1 and len(self.targets) == 1:
return ComponentMapper(
return ComponentMap(
self.sources[0],
self.targets[0],
rm.to_model(),
)
else:
return MultipleComponentMapper(
return MultiComponentMap(
self.sources, self.targets, rm.to_model(True)
)
else:
return ImplicitMapper(self.sources[0], self.targets[0])
return ImplicitComponentMap(self.sources[0], self.targets[0])


class FusionTimePatternMap(Struct, frozen=True):
"""Fusion-JSON payload for a date pattern map."""

source: str
target: str
freqId: str
pattern: str
locale: str
freqId: Optional[str] = None
freqDim: Optional[str] = None
id: Optional[str] = None

def to_model(self) -> DateMapper:
def to_model(self) -> DatePatternMap:
"""Returns the requested date mapper."""
return DateMapper(
freq = self.freqId if self.freqId else self.freqDim
typ = "fixed" if self.freqId else "variable"
return DatePatternMap(
self.source,
self.target,
self.pattern,
self.freqId,
freq, # type: ignore[arg-type]
self.id,
self.locale,
typ, # type: ignore[arg-type]
)


class FusionStructureMap(Struct, frozen=True):
"""Fusion-JSON payload for a structure map."""

id: str
agencyId: str
version: str
source: str
target: str
names: Sequence[FusionString] = ()
descriptions: Sequence[FusionString] = ()
fixedInput: Dict[str, Any] = {}
fixedOutput: Dict[str, Any] = {}
timePatternMaps: Sequence[FusionTimePatternMap] = ()
componentMaps: Sequence[FusionComponentMap] = ()

def to_model(
self,
rms: Sequence[FusionRepresentationMap],
) -> MappingDefinition:
) -> SM:
"""Returns the requested mapping definition."""
m1 = [tpm.to_model() for tpm in self.timePatternMaps]
m2 = [cm.to_model(rms) for cm in self.componentMaps]
m3 = [ValueSetter(k, v) for k, v in self.fixedOutput.items()]
m4 = [m for m in m2 if isinstance(m, ImplicitMapper)]
m5 = [m for m in m2 if isinstance(m, MultipleComponentMapper)]
m6 = [m for m in m2 if isinstance(m, ComponentMapper)]

return MappingDefinition(
component_maps=m6,
date_maps=m1,
fixed_value_maps=m3,
implicit_maps=m4,
multiple_component_maps=m5,
m1 = tuple(tpm.to_model() for tpm in self.timePatternMaps)
m2 = tuple(cm.to_model(rms) for cm in self.componentMaps)
m3 = tuple(FixedValueMap(k, v) for k, v in self.fixedOutput.items())
m4 = tuple(
FixedValueMap(k, v, "source") for k, v in self.fixedInput.items()
)

return SM(
self.id,
self.names[0].value,
self.agencyId,
self.source,
self.target,
m1 + m2 + m3 + m4,
self.descriptions[0].value if self.descriptions else None,
self.version,
)


Expand All @@ -163,7 +183,7 @@ class FusionMappingMessage(Struct, frozen=True):
StructureMap: Sequence[FusionStructureMap]
RepresentationMap: Sequence[FusionRepresentationMap] = ()

def to_model(self) -> MappingDefinition:
def to_model(self) -> SM:
"""Returns the requested mapping definition."""
return self.StructureMap[0].to_model(self.RepresentationMap)

Expand All @@ -173,7 +193,7 @@ class FusionRepresentationMapMessage(Struct, frozen=True):

RepresentationMap: Sequence[FusionRepresentationMap]

def to_model(self) -> MappingDefinition:
def to_model(self) -> SM:
"""Returns the requested mapping definition."""
out = self.RepresentationMap[0].to_model()
return out # type: ignore[return-value]
Loading

0 comments on commit c79ae2e

Please sign in to comment.