randonneur.utils ================ .. py:module:: randonneur.utils Attributes ---------- .. autoapisummary:: randonneur.utils.ALL_VERBS randonneur.utils.EXCLUDED_ATTRS randonneur.utils.SAFE_VERBS Classes ------- .. autoapisummary:: randonneur.utils.FlexibleLookupDict Functions --------- .. autoapisummary:: randonneur.utils.apply_mapping randonneur.utils.rescale_edge randonneur.utils.right_case Module Contents --------------- .. py:class:: FlexibleLookupDict(input_data: collections.abc.Iterable[dict], fields_filter: Optional[List[str]] = None, case_sensitive: bool = False) Bases: :py:obj:`collections.abc.Mapping` A Mapping is a generic container for associating key/value pairs. This class provides concrete generic implementations of all methods except for __getitem__, __iter__, and __len__. A dictionary that allow for more flexible matching of dictionaries against other dicts. `input_data` is a dictionary like `{"foo": {"first": True, "bar": 42}}`. We want to match this input against `{'first': True}` and get back `foo`. Here is an examples: ```python fld = FlexibleLookupDict( input_data=[ {"source": {"foo": "a", "bar": "b"}}, {"source": {"foo": "b"}}, ] ) fld[{"foo": "b"}] == {"source": {"foo": "b"}} >>> True ``` For real data we would have input data with both `source` and `target` (or `targets` for disaggregation) keys. This class makes the **strong assumption** that `input_data` has `source` and `target`/`targets` keys. We need to match a dictionary against another dictionary, but the other dictionary doesn't have a fixed set of keys - they can vary across all the possibilities. We therefore allow matching based on each unique combination of keys present. If `fields_filter` is given, then only consider keys present in that list. ```python fld = FlexibleLookupDict( input_data=[ {"source": {"foo": "a", "bar": "b"}}, {"source": {"foo": "b"}}, ], fields_filter=["foo"] ) fld[{"foo": "b", "other": "whatever"}] == {"source": {"foo": "b"}} >>> True ``` If `case_sensitive`, then do case-sensitive matching on values (not keys) when comparing strings. Here is an example of a *case-insensitve* match: ```python fld = FlexibleLookupDict( input_data=[ {"source": {"foo": "a", "bar": "b"}}, {"source": {"foo": "b"}}, ], case_sensitive=False ) fld[{"foo": "B"}] == {"source": {"foo": "b"}} >>> True ``` .. py:attribute:: _case_sensitive :value: False .. py:attribute:: _dict .. py:attribute:: _field_combinations .. py:function:: apply_mapping(migrations: dict, mapping: dict, verbs: List[str]) -> dict Apply the label changes in `mapping` to the transformations in `migrations`. .. py:function:: rescale_edge(edge: dict, factor: numbers.Number) -> dict Rescale edges, including formulas and uncertainty values, by a constant factor .. py:function:: right_case(value: Any, case_sensitive: bool) -> Any Convert strings to lower case, and lists to tuples. .. py:data:: ALL_VERBS :value: ['create', 'delete', 'replace', 'update', 'disaggregate'] .. py:data:: EXCLUDED_ATTRS :value: ('target', 'targets', 'source', 'conversion_factor') .. py:data:: SAFE_VERBS :value: ['update', 'replace', 'disaggregate']