Skip to main content

MappingTools. Do stuff with Mappings

Project description

MappingTools

This library provides utility functions for manipulating and transforming data structures which have or include Mapping-like characteristics. Including inverting dictionaries, converting class like objects to dictionaries, creating nested defaultdicts, and unwrapping complex objects.

Package PyPI - version PyPI - Status PyPI - Python Version PyPI - Downloads
GitHub GitHub repo size GitHub last commit (by committer) Contributors
Tools PyCharm Ruff uv
CI/CD Tests Publish
Scans Coverage
Quality Gate Status Security Rating Maintainability Rating Reliability Rating
Lines of Code Vulnerabilities Bugs
Codacy Quality Codacy Coverage

Usage

Transformers

distinct

Yields distinct values for a specified key across multiple mappings.

from mappingtools import distinct

mappings = [
    {'a': 1, 'b': 2},
    {'a': 2, 'b': 3},
    {'a': 1, 'b': 4}
]
distinct_values = list(distinct('a', *mappings))
print(distinct_values)
# Output: [1, 2]

keep

Yields subsets of mappings by retaining only the specified keys.

from mappingtools import keep

mappings = [
    {'a': 1, 'b': 2, 'c': 3},
    {'a': 4, 'b': 5, 'd': 6}
]
keys_to_keep = ['a', 'b']
result = list(keep(keys_to_keep, *mappings))
# result: [{'a': 1, 'b': 2}, {'a': 4, 'b': 5}]

remove

Yields mappings with specified keys removed. It takes an iterable of keys and multiple mappings, and returns a generator of mappings with those keys excluded.

from mappingtools import remove

mappings = [
    {'a': 1, 'b': 2, 'c': 3},
    {'a': 4, 'b': 5, 'd': 6}
]
keys_to_remove = ['a', 'b']
result = list(remove(keys_to_remove, *mappings))
# result: [{'c': 3}, {'d': 6}]

inverse

Swaps keys and values in a dictionary.

from mappingtools import inverse

original_mapping = {'a': {1, 2}, 'b': {3}}
inverted_mapping = inverse(original_mapping)
print(inverted_mapping)
# Output: defaultdict(<class 'set'>, {1: {'a'}, 2: {'a'}, 3: {'b'}})

flattened

The flattened function takes a nested mapping structure and converts it into a single-level dictionary by flattening the keys into tuples.

from mappingtools import flattened

nested_dict = {
    'a': {'b': 1, 'c': {'d': 2}},
    'e': 3
}
flat_dict = flattened(nested_dict)
# Expected output: {('a', 'b'): 1, ('a', 'c', 'd'): 2, ('e',): 3}

strictify

Strictify function applies a strict structural conversion to an object using optional converters for keys and values.

from mappingtools import strictify


def uppercase_key(key):
    return key.upper()


def double_value(value):
    return value * 2


data = {'a': 1, 'b': 2}
result = strictify(data, key_converter=uppercase_key, value_converter=double_value)
print(result)
# Output: {'A': 2, 'B': 4}

simplify

Converts objects to strictly structured dictionaries.

from collections import Counter
from dataclasses import dataclass
from datetime import datetime
from typing import Mapping

from mappingtools import simplify

data = {'key1': 'value1', 'key2': ['item1', 'item2']}
simplified_data = simplify(data)
print(simplified_data)
# Output: {'key1': 'value1', 'key2': ['item1', 'item2']}

counter = Counter({'a': 1, 'b': 2})
print(counter)
# Output: Counter({'b': 2, 'a': 1})

simplified_counter = simplify(counter)
print(simplified_counter)


# Output: {'a': 1, 'b': 2}


@dataclass
class SampleDataClass:
    a: int
    b: int
    aa: str
    bb: str
    c: list[int]
    d: Mapping
    e: datetime


sample_datetime = datetime(2024, 7, 22, 21, 42, 17, 314159)
sample_dataclass = SampleDataClass(1, 2, '11', '22', [1, 2], {'aaa': 111, 'bbb': '222'}, sample_datetime)

print(sample_dataclass)
# Output: SampleDataClass(a=1, b=2, aa='11', bb='22', c=[1, 2], d={'aaa': 111, 'bbb': '222'}, e=datetime.datetime(2024, 7, 22, 21, 42, 17, 314159))

simplified_sample_dataclass = simplify(sample_dataclass)
print(simplified_sample_dataclass)
# Output: {'a': 1, 'aa': '11', 'b': 2, 'bb': '22', 'c': [1, 2], 'd': {'aaa': 111, 'bbb': '222'}, 'e': datetime.datetime(2024, 7, 22, 21, 42, 17, 314159)}

listify

Transforms complex objects into a list of dictionaries with key and value pairs.

from mappingtools import listify

wrapped_data = {'key1': {'subkey': 'value'}, 'key2': ['item1', 'item2']}
unwrapped_data = listify(wrapped_data)
print(unwrapped_data)
# Output: [{'key': 'key1', 'value': [{'key': 'subkey', 'value': 'value'}]}, {'key': 'key2', 'value': ['item1', 'item2']}]

stream

Takes a mapping and an optional item factory function, and generates items from the mapping. If the item factory is provided, it applies the factory to each key-value pair before yielding.

from collections import namedtuple

from mappingtools import stream


def custom_factory(key, value):
    return f"{key}: {value}"


my_mapping = {'a': 1, 'b': 2, 'c': 3}

for item in stream(my_mapping, custom_factory):
    print(item)
# Output:
# a: 1
# b: 2
# c: 3


MyTuple = namedtuple('MyTuple', ['key', 'value'])
data = {'a': 1, 'b': 2}

for item in stream(data, MyTuple):
    print(item)


# Output:
# MyTuple(key='a', value=1)
# MyTuple(key='b', value=2)


def record(k, v):
    return {'key': k, 'value': v}


for item in stream(data, record):
    print(item)
# output:
# {'key': 'a', 'value': 1}
# {'key': 'b', 'value': 2}

stream_dict_records

generates dictionary records from a given mapping, where each record contains a key-value pair from the mapping with customizable key and value names.

from mappingtools import stream_dict_records

mapping = {'a': 1, 'b': 2}
records = stream_dict_records(mapping, key_name='letter', value_name='number')
for record in records:
    print(record)
# Output:
# {'letter': 'a', 'number': 1}
# {'letter': 'b', 'number': 2}

Collectors

nested_defaultdict

Creates a nested defaultdict with specified depth and factory.

from mappingtools import nested_defaultdict

nested_dd = nested_defaultdict(1, list)
nested_dd[0][1].append('value')
print(nested_dd)
# Output: defaultdict(<function nested_defaultdict.<locals>.factory at ...>, {0: defaultdict(<function nested_defaultdict.<locals>.factory at ...>, {1: ['value']})})

CategoryCounter

The CategoryCounter class extends a dictionary to count occurrences of data items categorized by multiple categories. It maintains a total count of all data items and allows categorization using direct values or functions.

from mappingtools import CategoryCounter

counter = CategoryCounter()

for fruit in ['apple', 'banana', 'apple']:
    counter.update({fruit: 1}, type='fruit', char_count=len(fruit), unique_char_count=len(set(fruit)))

print(counter.total)
# Output: Counter({'apple': 2, 'banana': 1})

print(counter)
# Output: CategoryCounter({'type': defaultdict(<class 'collections.Counter'>, {'fruit': Counter({'apple': 2, 'banana': 1})}), 'char_count': defaultdict(<class 'collections.Counter'>, {5: Counter({'apple': 2}), 6: Counter({'banana': 1})}), 'unique_char_count': defaultdict(<class 'collections.Counter'>, {4: Counter({'apple': 2}), 3: Counter({'banana': 1})})})

MappingCollector

A class designed to collect key-value pairs into an internal mapping based on different modes. It supports modes like ALL, COUNT, DISTINCT, FIRST, and LAST, each dictating how key-value pairs are collected.

from mappingtools import MappingCollector, MappingCollectorMode

collector = MappingCollector(MappingCollectorMode.ALL)
collector.add('a', 1)
collector.add('a', 2)
collector.collect([('b', 3), ('b', 4)])
print(collector.mapping)
# Output: {'a': [1, 2], 'b': [3, 4]}

Development

Ruff

ruff check src

Test

Standard (cobertura) XML Coverage Report

python -m pytest tests -n auto --cov=src --cov-branch --doctest-modules --cov-report=xml

HTML Coverage Report

python -m pytest tests -n auto --cov=src --cov-branch --doctest-modules --cov-report=html

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

mappingtools-0.2.2.tar.gz (26.5 kB view details)

Uploaded Source

Built Distribution

mappingtools-0.2.2-py3-none-any.whl (9.5 kB view details)

Uploaded Python 3

File details

Details for the file mappingtools-0.2.2.tar.gz.

File metadata

  • Download URL: mappingtools-0.2.2.tar.gz
  • Upload date:
  • Size: 26.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.9.20

File hashes

Hashes for mappingtools-0.2.2.tar.gz
Algorithm Hash digest
SHA256 ecb62596207a5b167ef774fecfeb77c797262527ba888d08878e4e67666cfceb
MD5 45206c74b52eb4f43d2ad31a7bd3e016
BLAKE2b-256 9fb1fd8e319fad786b3d32609673f9733924bb9ca113b66f7d36217443488060

See more details on using hashes here.

File details

Details for the file mappingtools-0.2.2-py3-none-any.whl.

File metadata

File hashes

Hashes for mappingtools-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 eed4eae5ec41bc8a1cbd63ea56bcc8eb7820c8b778c22eb4c99e01102a880f8b
MD5 65433f400ac9eb194e59a5552d4dd588
BLAKE2b-256 b359139e483562bd8260818566e0b89be5773c095cf5d234f677d4c3f78adc47

See more details on using hashes here.

Supported by

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