Skip to main content

A tool for mapping and transforming dictionaries based on predefined rules.

Project description

Dictionary Mapper

PyPI - Version PyPI - Python Version


Table of Contents

Usage

This library can map a source dictionary and generate a target new one following dot notation in source and target dictionaries.

Example:

  1. Define a SpecEntry dict, keys are the source dict paths, values are the target dict paths:
from dictionary_mapper import SpecEntry


spec: SpecEntry = {
    "body.int_field": "int_field",
    "body.str_field": "str_field",
    "body.complex_field.nested_int": {
        "path": "complex_field.nested_int",
        "default": 0,
        "transform": lambda x: cast("int", x) * 2,
    },
    "body.complex_field.nested_str": "complex_field.nested_str",
    "body.list[0].str_field": "list_field",
    "body.int_list": "int_list",
    "body.str_list": "str_list",
}
  1. For raw dict output, then use the RawDictionaryMapper class
...
from typing import cast
from dictionary_mapper import RawDictionaryMapper
...


src: dict[str, object] = {
    "body": {
        "int_field": 10,
        "str_field": "hello",
        "complex_field": {
            "nested_int": 5,
            "nested_str": "world",
        },
        "list": [
            {
                "str_field": "test field",
            },
        ],
        "int_list": [1, 2, 3],
        "str_list": ["1", "2", "3"],
    },
}


dm: RawDictionaryMapper = RawDictionaryMapper()

maped_dict: dict[str, object] = dm.create_transformed_dict(src, spec)

assert maped_dict["int_field"] == 10
assert maped_dict["str_field"] == "hello"
assert cast("dict[str, object]", maped_dict["complex_field"])["nested_int"] == 10  # Transformed
assert cast("dict[str, object]", maped_dict["complex_field"])["nested_str"] == "world"
assert maped_dict["list_field"] == "test field"
assert maped_dict["int_list"] == [1, 2, 3]
assert maped_dict["str_list"] == ["1", "2", "3"]
  1. For TypedDicts you can use the TypedDictionaryMapper as follows
...
from dictionary_mapper import TypedDictionaryMapper
...


class MyNestedDict(TypedDict):
    nested_int: int
    nested_str: str


class MyTypedDict(TypedDict):
    int_field: int
    str_field: str
    complex_field: MyNestedDict
    list_field: str
    int_list: list[int]
    str_list: list[str]

...

dm: TypedDictionaryMapper[MyTypedDict] = TypedDictionaryMapper()

maped_dict: MyTypedDict = dm.create_transformed_dict(src, spec)

assert maped_dict["int_field"] == 10
assert maped_dict["str_field"] == "hello"
assert maped_dict["complex_field"]["nested_int"] == 10  # Transformed
assert maped_dict["complex_field"]["nested_str"] == "world"
assert maped_dict["list_field"] == "test field"
assert maped_dict["int_list"] == [1, 2, 3]
assert maped_dict["str_list"] == ["1", "2", "3"]
  1. You can add complex lists on the target, but you'll need to add allways the index to that lists, otherwhise will be recognized as primitive value.
src = {
    ...
    "complex_list": [
        {
            "nested_int": 10,
            "nested_str": "complex",
        },
        {"nested_int": 5},
        {},
        {
            "nested_str": "double complex",
        },
    ],
    ...
}

...

spec = {
    ...
    "body.complex_list[0].nested_int": "complex_list[1].secondary_field[0].secondary_int",
    "body.complex_list[0].nested_str": "complex_list[1].secondary_field[3].secondary_str",
    "body.complex_list[2].nested_int": "complex_list[1].secondary_field[1].secondary_int",
    "body.complex_list[3].nested_str": "complex_list[1].secondary_field[2].secondary_str",
    "body.complex_list[1].nested_int": {
        "path": "complex_list[0].secondary_field[1].secondary_int",
        "default": 0,
        "transform": lambda x: cast("int", x) * 2,
    },
    ...
}

...

EXPECTED_INT_FIELD = 10

assert maped_dict["complex_list"][1]["secondary_field"][0]["secondary_int"] == EXPECTED_INT_FIELD
assert maped_dict["complex_list"][1]["secondary_field"][3]["secondary_str"] == "complex"
assert maped_dict["complex_list"][1]["secondary_field"][1]["secondary_int"] is None
assert maped_dict["complex_list"][1]["secondary_field"][2]["secondary_str"] == "double complex"
assert maped_dict["complex_list"][0]["secondary_field"][1]["secondary_int"] == EXPECTED_INT_FIELD  # Transformed

Installation

Add recommended extensions at .vscode/extensions.json. Then run:

pip install hatch hatch-pip-deepfreeze
hatch shell

These two commands creates everithing for you and vscode to start working ASAP.

License

dictionary-mapper is distributed under the terms of the MIT license.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dictionary_mapper-0.2.0.tar.gz (4.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dictionary_mapper-0.2.0-py3-none-any.whl (4.2 kB view details)

Uploaded Python 3

File details

Details for the file dictionary_mapper-0.2.0.tar.gz.

File metadata

  • Download URL: dictionary_mapper-0.2.0.tar.gz
  • Upload date:
  • Size: 4.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for dictionary_mapper-0.2.0.tar.gz
Algorithm Hash digest
SHA256 8192dcbfbef2bd85a06e85861b7d07b759d47b37f276add3f320d31e6aa2a51b
MD5 83d10dbf386c67d51cd3d003db613c85
BLAKE2b-256 3983fd62838fcdf353e671ae127bb135db0fd00b5bd4f2cd5a4280b24ecfbd0c

See more details on using hashes here.

File details

Details for the file dictionary_mapper-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for dictionary_mapper-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 edb1fb593d3f984e5436f15eae6f2abe1e34e51e61da2e87a270092700e2b615
MD5 8d3a9821e341e3161e14b4c838d0bbd1
BLAKE2b-256 d8642d86649552faaa57731df359996edc0e3d0ce636ad2929ac54cccec82477

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page