Skip to main content

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

Project description

Dictionary Mapper

GitHub tag 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.3.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.3.0-py3-none-any.whl (4.2 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: dictionary_mapper-0.3.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.3.0.tar.gz
Algorithm Hash digest
SHA256 0258afe269562701394e1d95685ada0e16b2846d5f69a5c5498fe8aa8fd97999
MD5 03dfac919de2c8b5bd28e46ab48e2cf9
BLAKE2b-256 0c111bf265b7c2591e10df2f69ad8735b3003b363d719e2d09415719b62513f7

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for dictionary_mapper-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 94f2fee6f3e34822558704690d847a5cf7d4f881e46b71c9342ee5389174e80a
MD5 0f8387035f21d83c450089084014a393
BLAKE2b-256 87608f3d4ef90e2bbce7f02e4b433a959a36259713d6ff62985118c9f5c3ab5d

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