mappingtools


Namemappingtools JSON
Version 0.2.2 PyPI version JSON
download
home_pageNone
SummaryMappingTools. Do stuff with Mappings
upload_time2024-10-18 21:04:15
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseNone
keywords mapping manipulate mutate transform
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # 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.

<table>
  <tr style="vertical-align: middle;">
    <td>Package</td>
    <td>
      <img alt="PyPI - version" src="https://img.shields.io/pypi/v/mappingtools">
      <img alt="PyPI - Status" src="https://img.shields.io/pypi/status/mappingtools">
      <img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/mappingtools">
      <img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dd/mappingtools">
      <br>
      <img alt="GitHub" src="https://img.shields.io/github/license/erivlis/mappingtools">
      <img alt="GitHub repo size" src="https://img.shields.io/github/repo-size/erivlis/mappingtools">
      <img alt="GitHub last commit (by committer)" src="https://img.shields.io/github/last-commit/erivlis/mappingtools">
      <a href="https://github.com/erivlis/mappingtools/graphs/contributors"><img alt="Contributors" src="https://img.shields.io/github/contributors/erivlis/mappingtools.svg"></a>
    </td>
  </tr>
  <tr>
    <td>Tools</td>
    <td>
      <a href="https://www.jetbrains.com/pycharm/"><img alt="PyCharm" src="https://img.shields.io/badge/PyCharm-FCF84A.svg?logo=PyCharm&logoColor=black&labelColor=21D789&color=FCF84A"></a>
      <a href="https://github.com/astral-sh/ruff"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff" style="max-width:100%;"></a>
      <a href="https://github.com/astral-sh/uv"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json" alt="uv" style="max-width:100%;"></a>
      <!-- a href="https://squidfunk.github.io/mkdocs-material/"><img src="https://img.shields.io/badge/Material_for_MkDocs-526CFE?&logo=MaterialForMkDocs&logoColor=white&labelColor=grey"></a -->
    </td>
  </tr>
  <tr>
    <td>CI/CD</td>
    <td>
      <a href="https://github.com/erivlis/mappingtools/actions/workflows/test.yml"><img alt="Tests" src="https://github.com/erivlis/mappingtools/actions/workflows/test.yml/badge.svg?branch=main"></a>
      <a href="https://github.com/erivlis/mappingtools/actions/workflows/publish.yml"><img alt="Publish" src="https://github.com/erivlis/mappingtools/actions/workflows/publish.yml/badge.svg"></a>
      <!--a href="https://github.com/erivlis/mappingtools/actions/workflows/publish-docs.yaml"><img alt="Publish Docs" src="https://github.com/erivlis/mappingtools/actions/workflows/publish-docs.yaml/badge.svg"></a-->
    </td>
  </tr>
  <tr>
    <td>Scans</td>
    <td>
      <a href="https://codecov.io/gh/erivlis/mappingtools"><img alt="Coverage" src="https://codecov.io/gh/erivlis/mappingtools/graph/badge.svg?token=POODT8M9NV"/></a>
      <br>
      <a href="https://sonarcloud.io/summary/new_code?id=erivlis_mappingtools"><img alt="Quality Gate Status" src="https://sonarcloud.io/api/project_badges/measure?project=erivlis_mappingtools&metric=alert_status"></a>
      <a href="https://sonarcloud.io/summary/new_code?id=erivlis_mappingtools"><img alt="Security Rating" src="https://sonarcloud.io/api/project_badges/measure?project=erivlis_mappingtools&metric=security_rating"></a>
      <a href="https://sonarcloud.io/summary/new_code?id=erivlis_mappingtools"><img alt="Maintainability Rating" src="https://sonarcloud.io/api/project_badges/measure?project=erivlis_mappingtools&metric=sqale_rating"></a>
      <a href="https://sonarcloud.io/summary/new_code?id=erivlis_mappingtools"><img alt="Reliability Rating" src="https://sonarcloud.io/api/project_badges/measure?project=erivlis_mappingtools&metric=reliability_rating"></a>
      <br>
      <a href="https://sonarcloud.io/summary/new_code?id=erivlis_mappingtools"><img alt="Lines of Code" src="https://sonarcloud.io/api/project_badges/measure?project=erivlis_mappingtools&metric=ncloc"></a>
      <a href="https://sonarcloud.io/summary/new_code?id=erivlis_mappingtools"><img alt="Vulnerabilities" src="https://sonarcloud.io/api/project_badges/measure?project=erivlis_mappingtools&metric=vulnerabilities"></a>
      <a href="https://sonarcloud.io/summary/new_code?id=erivlis_mappingtools"><img alt="Bugs" src="https://sonarcloud.io/api/project_badges/measure?project=erivlis_mappingtools&metric=bugs"></a>
      <br>
      <a href="https://app.codacy.com/gh/erivlis/mappingtools/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade"><img alt="Codacy Quality" src="https://app.codacy.com/project/badge/Grade/8b83a99f939b4883ae2f37d7ec3419d1"></a>
      <a href="https://app.codacy.com/gh/erivlis/mappingtools/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_coverage"><img alt="Codacy Coverage" src="https://app.codacy.com/project/badge/Coverage/8b83a99f939b4883ae2f37d7ec3419d1"/></a>
    </td>
  </tr>
</table>

## Usage

### Transformers

#### `distinct`

Yields distinct values for a specified key across multiple mappings.

<!-- name: test_distinct -->

```python
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.

<!-- name: test_keep -->

```python
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.

<!-- name: test_remove -->

```python
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.

<!-- name: test_inverse -->

```python
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.

<!-- name: test_flattened -->

```python
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.

<!-- name: test_strictify -->

```python
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.

<!-- name: test_simplify -->

```python
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.

<!-- name: test_listify -->

```python
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.

<!-- name: test_stream -->

```python
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.

<!-- name: test_stream_dict_records -->

```python
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.

<!-- name: test_nested_defaultdict -->

```python
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.

<!-- name: test_category_counter -->

```python
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.

<!-- name: test_mapping_collector -->

```python
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

```shell
ruff check src
```

### Test

#### Standard (cobertura) XML Coverage Report

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

#### HTML Coverage Report

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

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "mappingtools",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "Mapping, manipulate, mutate, transform",
    "author": null,
    "author_email": "Eran Rivlis <eran@rivlis.info>",
    "download_url": "https://files.pythonhosted.org/packages/9f/b1/fd8e319fad786b3d32609673f9733924bb9ca113b66f7d36217443488060/mappingtools-0.2.2.tar.gz",
    "platform": null,
    "description": "# MappingTools\n\nThis library provides utility functions for manipulating and transforming data structures which have or include\nMapping-like characteristics. Including inverting dictionaries, converting class like objects to dictionaries, creating\nnested defaultdicts, and unwrapping complex objects.\n\n<table>\n  <tr style=\"vertical-align: middle;\">\n    <td>Package</td>\n    <td>\n      <img alt=\"PyPI - version\" src=\"https://img.shields.io/pypi/v/mappingtools\">\n      <img alt=\"PyPI - Status\" src=\"https://img.shields.io/pypi/status/mappingtools\">\n      <img alt=\"PyPI - Python Version\" src=\"https://img.shields.io/pypi/pyversions/mappingtools\">\n      <img alt=\"PyPI - Downloads\" src=\"https://img.shields.io/pypi/dd/mappingtools\">\n      <br>\n      <img alt=\"GitHub\" src=\"https://img.shields.io/github/license/erivlis/mappingtools\">\n      <img alt=\"GitHub repo size\" src=\"https://img.shields.io/github/repo-size/erivlis/mappingtools\">\n      <img alt=\"GitHub last commit (by committer)\" src=\"https://img.shields.io/github/last-commit/erivlis/mappingtools\">\n      <a href=\"https://github.com/erivlis/mappingtools/graphs/contributors\"><img alt=\"Contributors\" src=\"https://img.shields.io/github/contributors/erivlis/mappingtools.svg\"></a>\n    </td>\n  </tr>\n  <tr>\n    <td>Tools</td>\n    <td>\n      <a href=\"https://www.jetbrains.com/pycharm/\"><img alt=\"PyCharm\" src=\"https://img.shields.io/badge/PyCharm-FCF84A.svg?logo=PyCharm&logoColor=black&labelColor=21D789&color=FCF84A\"></a>\n      <a href=\"https://github.com/astral-sh/ruff\"><img src=\"https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json\" alt=\"Ruff\" style=\"max-width:100%;\"></a>\n      <a href=\"https://github.com/astral-sh/uv\"><img src=\"https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json\" alt=\"uv\" style=\"max-width:100%;\"></a>\n      <!-- a href=\"https://squidfunk.github.io/mkdocs-material/\"><img src=\"https://img.shields.io/badge/Material_for_MkDocs-526CFE?&logo=MaterialForMkDocs&logoColor=white&labelColor=grey\"></a -->\n    </td>\n  </tr>\n  <tr>\n    <td>CI/CD</td>\n    <td>\n      <a href=\"https://github.com/erivlis/mappingtools/actions/workflows/test.yml\"><img alt=\"Tests\" src=\"https://github.com/erivlis/mappingtools/actions/workflows/test.yml/badge.svg?branch=main\"></a>\n      <a href=\"https://github.com/erivlis/mappingtools/actions/workflows/publish.yml\"><img alt=\"Publish\" src=\"https://github.com/erivlis/mappingtools/actions/workflows/publish.yml/badge.svg\"></a>\n      <!--a href=\"https://github.com/erivlis/mappingtools/actions/workflows/publish-docs.yaml\"><img alt=\"Publish Docs\" src=\"https://github.com/erivlis/mappingtools/actions/workflows/publish-docs.yaml/badge.svg\"></a-->\n    </td>\n  </tr>\n  <tr>\n    <td>Scans</td>\n    <td>\n      <a href=\"https://codecov.io/gh/erivlis/mappingtools\"><img alt=\"Coverage\" src=\"https://codecov.io/gh/erivlis/mappingtools/graph/badge.svg?token=POODT8M9NV\"/></a>\n      <br>\n      <a href=\"https://sonarcloud.io/summary/new_code?id=erivlis_mappingtools\"><img alt=\"Quality Gate Status\" src=\"https://sonarcloud.io/api/project_badges/measure?project=erivlis_mappingtools&metric=alert_status\"></a>\n      <a href=\"https://sonarcloud.io/summary/new_code?id=erivlis_mappingtools\"><img alt=\"Security Rating\" src=\"https://sonarcloud.io/api/project_badges/measure?project=erivlis_mappingtools&metric=security_rating\"></a>\n      <a href=\"https://sonarcloud.io/summary/new_code?id=erivlis_mappingtools\"><img alt=\"Maintainability Rating\" src=\"https://sonarcloud.io/api/project_badges/measure?project=erivlis_mappingtools&metric=sqale_rating\"></a>\n      <a href=\"https://sonarcloud.io/summary/new_code?id=erivlis_mappingtools\"><img alt=\"Reliability Rating\" src=\"https://sonarcloud.io/api/project_badges/measure?project=erivlis_mappingtools&metric=reliability_rating\"></a>\n      <br>\n      <a href=\"https://sonarcloud.io/summary/new_code?id=erivlis_mappingtools\"><img alt=\"Lines of Code\" src=\"https://sonarcloud.io/api/project_badges/measure?project=erivlis_mappingtools&metric=ncloc\"></a>\n      <a href=\"https://sonarcloud.io/summary/new_code?id=erivlis_mappingtools\"><img alt=\"Vulnerabilities\" src=\"https://sonarcloud.io/api/project_badges/measure?project=erivlis_mappingtools&metric=vulnerabilities\"></a>\n      <a href=\"https://sonarcloud.io/summary/new_code?id=erivlis_mappingtools\"><img alt=\"Bugs\" src=\"https://sonarcloud.io/api/project_badges/measure?project=erivlis_mappingtools&metric=bugs\"></a>\n      <br>\n      <a href=\"https://app.codacy.com/gh/erivlis/mappingtools/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade\"><img alt=\"Codacy Quality\" src=\"https://app.codacy.com/project/badge/Grade/8b83a99f939b4883ae2f37d7ec3419d1\"></a>\n      <a href=\"https://app.codacy.com/gh/erivlis/mappingtools/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_coverage\"><img alt=\"Codacy Coverage\" src=\"https://app.codacy.com/project/badge/Coverage/8b83a99f939b4883ae2f37d7ec3419d1\"/></a>\n    </td>\n  </tr>\n</table>\n\n## Usage\n\n### Transformers\n\n#### `distinct`\n\nYields distinct values for a specified key across multiple mappings.\n\n<!-- name: test_distinct -->\n\n```python\nfrom mappingtools import distinct\n\nmappings = [\n    {'a': 1, 'b': 2},\n    {'a': 2, 'b': 3},\n    {'a': 1, 'b': 4}\n]\ndistinct_values = list(distinct('a', *mappings))\nprint(distinct_values)\n# Output: [1, 2]\n```\n\n#### `keep`\n\nYields subsets of mappings by retaining only the specified keys.\n\n<!-- name: test_keep -->\n\n```python\nfrom mappingtools import keep\n\nmappings = [\n    {'a': 1, 'b': 2, 'c': 3},\n    {'a': 4, 'b': 5, 'd': 6}\n]\nkeys_to_keep = ['a', 'b']\nresult = list(keep(keys_to_keep, *mappings))\n# result: [{'a': 1, 'b': 2}, {'a': 4, 'b': 5}]\n```\n\n#### `remove`\n\nYields mappings with specified keys removed. It takes an iterable of keys and multiple mappings, and returns a generator\nof mappings with those keys excluded.\n\n<!-- name: test_remove -->\n\n```python\nfrom mappingtools import remove\n\nmappings = [\n    {'a': 1, 'b': 2, 'c': 3},\n    {'a': 4, 'b': 5, 'd': 6}\n]\nkeys_to_remove = ['a', 'b']\nresult = list(remove(keys_to_remove, *mappings))\n# result: [{'c': 3}, {'d': 6}]\n```\n\n#### `inverse`\n\nSwaps keys and values in a dictionary.\n\n<!-- name: test_inverse -->\n\n```python\nfrom mappingtools import inverse\n\noriginal_mapping = {'a': {1, 2}, 'b': {3}}\ninverted_mapping = inverse(original_mapping)\nprint(inverted_mapping)\n# Output: defaultdict(<class 'set'>, {1: {'a'}, 2: {'a'}, 3: {'b'}})\n```\n\n#### `flattened`\n\nThe flattened function takes a nested mapping structure and converts it into a single-level dictionary by flattening the\nkeys into tuples.\n\n<!-- name: test_flattened -->\n\n```python\nfrom mappingtools import flattened\n\nnested_dict = {\n    'a': {'b': 1, 'c': {'d': 2}},\n    'e': 3\n}\nflat_dict = flattened(nested_dict)\n# Expected output: {('a', 'b'): 1, ('a', 'c', 'd'): 2, ('e',): 3}\n```\n\n#### `strictify`\n\nStrictify function applies a strict structural conversion to an object using optional converters for keys and values.\n\n<!-- name: test_strictify -->\n\n```python\nfrom mappingtools import strictify\n\n\ndef uppercase_key(key):\n    return key.upper()\n\n\ndef double_value(value):\n    return value * 2\n\n\ndata = {'a': 1, 'b': 2}\nresult = strictify(data, key_converter=uppercase_key, value_converter=double_value)\nprint(result)\n# Output: {'A': 2, 'B': 4}\n```\n\n#### `simplify`\n\nConverts objects to strictly structured dictionaries.\n\n<!-- name: test_simplify -->\n\n```python\nfrom collections import Counter\nfrom dataclasses import dataclass\nfrom datetime import datetime\nfrom typing import Mapping\n\nfrom mappingtools import simplify\n\ndata = {'key1': 'value1', 'key2': ['item1', 'item2']}\nsimplified_data = simplify(data)\nprint(simplified_data)\n# Output: {'key1': 'value1', 'key2': ['item1', 'item2']}\n\ncounter = Counter({'a': 1, 'b': 2})\nprint(counter)\n# Output: Counter({'b': 2, 'a': 1})\n\nsimplified_counter = simplify(counter)\nprint(simplified_counter)\n\n\n# Output: {'a': 1, 'b': 2}\n\n\n@dataclass\nclass SampleDataClass:\n    a: int\n    b: int\n    aa: str\n    bb: str\n    c: list[int]\n    d: Mapping\n    e: datetime\n\n\nsample_datetime = datetime(2024, 7, 22, 21, 42, 17, 314159)\nsample_dataclass = SampleDataClass(1, 2, '11', '22', [1, 2], {'aaa': 111, 'bbb': '222'}, sample_datetime)\n\nprint(sample_dataclass)\n# 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))\n\nsimplified_sample_dataclass = simplify(sample_dataclass)\nprint(simplified_sample_dataclass)\n# 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)}\n```\n\n#### `listify`\n\nTransforms complex objects into a list of dictionaries with key and value pairs.\n\n<!-- name: test_listify -->\n\n```python\nfrom mappingtools import listify\n\nwrapped_data = {'key1': {'subkey': 'value'}, 'key2': ['item1', 'item2']}\nunwrapped_data = listify(wrapped_data)\nprint(unwrapped_data)\n# Output: [{'key': 'key1', 'value': [{'key': 'subkey', 'value': 'value'}]}, {'key': 'key2', 'value': ['item1', 'item2']}]\n```\n\n#### `stream`\n\nTakes a mapping and an optional item factory function, and generates items from the mapping.\nIf the item factory is provided, it applies the factory to each key-value pair before yielding.\n\n<!-- name: test_stream -->\n\n```python\nfrom collections import namedtuple\n\nfrom mappingtools import stream\n\n\ndef custom_factory(key, value):\n    return f\"{key}: {value}\"\n\n\nmy_mapping = {'a': 1, 'b': 2, 'c': 3}\n\nfor item in stream(my_mapping, custom_factory):\n    print(item)\n# Output:\n# a: 1\n# b: 2\n# c: 3\n\n\nMyTuple = namedtuple('MyTuple', ['key', 'value'])\ndata = {'a': 1, 'b': 2}\n\nfor item in stream(data, MyTuple):\n    print(item)\n\n\n# Output:\n# MyTuple(key='a', value=1)\n# MyTuple(key='b', value=2)\n\n\ndef record(k, v):\n    return {'key': k, 'value': v}\n\n\nfor item in stream(data, record):\n    print(item)\n# output:\n# {'key': 'a', 'value': 1}\n# {'key': 'b', 'value': 2}\n```\n\n#### `stream_dict_records`\n\ngenerates dictionary records from a given mapping, where each record contains a key-value pair from the mapping with\ncustomizable key and value names.\n\n<!-- name: test_stream_dict_records -->\n\n```python\nfrom mappingtools import stream_dict_records\n\nmapping = {'a': 1, 'b': 2}\nrecords = stream_dict_records(mapping, key_name='letter', value_name='number')\nfor record in records:\n    print(record)\n# Output:\n# {'letter': 'a', 'number': 1}\n# {'letter': 'b', 'number': 2}\n```\n\n### Collectors\n\n#### `nested_defaultdict`\n\nCreates a nested defaultdict with specified depth and factory.\n\n<!-- name: test_nested_defaultdict -->\n\n```python\nfrom mappingtools import nested_defaultdict\n\nnested_dd = nested_defaultdict(1, list)\nnested_dd[0][1].append('value')\nprint(nested_dd)\n# Output: defaultdict(<function nested_defaultdict.<locals>.factory at ...>, {0: defaultdict(<function nested_defaultdict.<locals>.factory at ...>, {1: ['value']})})\n```\n\n#### `CategoryCounter`\n\nThe CategoryCounter class extends a dictionary to count occurrences of data items categorized by multiple categories.\nIt maintains a total count of all data items and allows categorization using direct values or functions.\n\n<!-- name: test_category_counter -->\n\n```python\nfrom mappingtools import CategoryCounter\n\ncounter = CategoryCounter()\n\nfor fruit in ['apple', 'banana', 'apple']:\n    counter.update({fruit: 1}, type='fruit', char_count=len(fruit), unique_char_count=len(set(fruit)))\n\nprint(counter.total)\n# Output: Counter({'apple': 2, 'banana': 1})\n\nprint(counter)\n# 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})})})\n```\n\n#### `MappingCollector`\n\nA class designed to collect key-value pairs into an internal mapping based on different modes.\nIt supports modes like ALL, COUNT, DISTINCT, FIRST, and LAST, each dictating how key-value pairs are\ncollected.\n\n<!-- name: test_mapping_collector -->\n\n```python\nfrom mappingtools import MappingCollector, MappingCollectorMode\n\ncollector = MappingCollector(MappingCollectorMode.ALL)\ncollector.add('a', 1)\ncollector.add('a', 2)\ncollector.collect([('b', 3), ('b', 4)])\nprint(collector.mapping)\n# Output: {'a': [1, 2], 'b': [3, 4]}\n```\n\n## Development\n\n### Ruff\n\n```shell\nruff check src\n```\n\n### Test\n\n#### Standard (cobertura) XML Coverage Report\n\n```shell\npython -m pytest tests -n auto --cov=src --cov-branch --doctest-modules --cov-report=xml\n```\n\n#### HTML Coverage Report\n\n```shell\npython -m pytest tests -n auto --cov=src --cov-branch --doctest-modules --cov-report=html\n```",
    "bugtrack_url": null,
    "license": null,
    "summary": "MappingTools. Do stuff with Mappings",
    "version": "0.2.2",
    "project_urls": {
        "Bug Tracker": "https://github.com/erivlis/mappingtools/issues",
        "Homepage": "https://erivlis.github.io/mappingtools",
        "Source": "https://github.com/erivlis/mappingtools"
    },
    "split_keywords": [
        "mapping",
        " manipulate",
        " mutate",
        " transform"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "b359139e483562bd8260818566e0b89be5773c095cf5d234f677d4c3f78adc47",
                "md5": "65433f400ac9eb194e59a5552d4dd588",
                "sha256": "eed4eae5ec41bc8a1cbd63ea56bcc8eb7820c8b778c22eb4c99e01102a880f8b"
            },
            "downloads": -1,
            "filename": "mappingtools-0.2.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "65433f400ac9eb194e59a5552d4dd588",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 9526,
            "upload_time": "2024-10-18T21:04:13",
            "upload_time_iso_8601": "2024-10-18T21:04:13.685609Z",
            "url": "https://files.pythonhosted.org/packages/b3/59/139e483562bd8260818566e0b89be5773c095cf5d234f677d4c3f78adc47/mappingtools-0.2.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "9fb1fd8e319fad786b3d32609673f9733924bb9ca113b66f7d36217443488060",
                "md5": "45206c74b52eb4f43d2ad31a7bd3e016",
                "sha256": "ecb62596207a5b167ef774fecfeb77c797262527ba888d08878e4e67666cfceb"
            },
            "downloads": -1,
            "filename": "mappingtools-0.2.2.tar.gz",
            "has_sig": false,
            "md5_digest": "45206c74b52eb4f43d2ad31a7bd3e016",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 26456,
            "upload_time": "2024-10-18T21:04:15",
            "upload_time_iso_8601": "2024-10-18T21:04:15.344108Z",
            "url": "https://files.pythonhosted.org/packages/9f/b1/fd8e319fad786b3d32609673f9733924bb9ca113b66f7d36217443488060/mappingtools-0.2.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-10-18 21:04:15",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "erivlis",
    "github_project": "mappingtools",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "mappingtools"
}
        
Elapsed time: 0.39412s