python-benedict


Namepython-benedict JSON
Version 0.33.2 PyPI version JSON
download
home_page
Summarypython-benedict is a dict subclass with keylist/keypath/keyattr support, normalized I/O operations (base64, csv, ini, json, pickle, plist, query-string, toml, xls, xml, yaml) and many utilities... for humans, obviously.
upload_time2024-03-04 23:25:42
maintainer
docs_urlNone
author
requires_python
licenseMIT License Copyright (c) 2019-present Fabio Caccamo Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords python dictionary dictionaries dict benedict subclass extended keylist keypath utility io data file url read write parse configparser config cfg pickle plist base64 csv html ini json query-string toml xml yaml clean clone deepclone deepupdate dump filter flatten groupby invert merge move nest remove rename search standardize subset swap traverse unflatten unique
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            [![](https://img.shields.io/pypi/pyversions/python-benedict.svg?color=blue&logo=python&logoColor=white)](https://www.python.org/)
[![](https://img.shields.io/pypi/v/python-benedict.svg?color=blue&logo=pypi&logoColor=white)](https://pypi.org/project/python-benedict/)
[![](https://static.pepy.tech/badge/python-benedict/month)](https://pepy.tech/project/python-benedict)
[![](https://img.shields.io/github/stars/fabiocaccamo/python-benedict?logo=github&style=flat)](https://github.com/fabiocaccamo/python-benedict/stargazers)
[![](https://img.shields.io/pypi/l/python-benedict.svg?color=blue)](https://github.com/fabiocaccamo/python-benedict/blob/main/LICENSE.txt)

[![](https://results.pre-commit.ci/badge/github/fabiocaccamo/python-benedict/main.svg)](https://results.pre-commit.ci/latest/github/fabiocaccamo/python-benedict/main)
[![](https://img.shields.io/github/actions/workflow/status/fabiocaccamo/python-benedict/test-package.yml?branch=main&label=build&logo=github)](https://github.com/fabiocaccamo/python-benedict)
[![](https://img.shields.io/codecov/c/gh/fabiocaccamo/python-benedict?logo=codecov)](https://codecov.io/gh/fabiocaccamo/python-benedict)
[![](https://img.shields.io/codeclimate/maintainability/fabiocaccamo/python-benedict?logo=code-climate)](https://codeclimate.com/github/fabiocaccamo/python-benedict/)
[![](https://img.shields.io/codacy/grade/0dbd5cc2089f4dce80a0e49e6822be3c?logo=codacy)](https://www.codacy.com/app/fabiocaccamo/python-benedict)
[![](https://img.shields.io/scrutinizer/quality/g/fabiocaccamo/python-benedict?logo=scrutinizer)](https://scrutinizer-ci.com/g/fabiocaccamo/python-benedict/?branch=main)
[![](https://img.shields.io/badge/code%20style-black-000000.svg?logo=python&logoColor=black)](https://github.com/psf/black)
[![](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)

# python-benedict
python-benedict is a dict subclass with **keylist/keypath/keyattr** support, **I/O** shortcuts (`base64`, `cli`, `csv`, `html`, `ini`, `json`, `pickle`, `plist`, `query-string`, `toml`, `xls`, `xml`, `yaml`) and many **utilities**... for humans, obviously.

## Features
-   100% **backward-compatible**, you can safely wrap existing dictionaries.
-   `NEW` **Keyattr** support for get/set items using **keys as attributes**.
-   **Keylist** support using **list of keys** as key.
-   **Keypath** support using **keypath-separator** *(dot syntax by default)*.
-   Keypath **list-index** support  *(also negative)* using the standard `[n]` suffix.
-   Normalized **I/O operations** with most common formats: `base64`, `cli`, `csv`, `html`, `ini`, `json`, `pickle`, `plist`, `query-string`, `toml`, `xls`, `xml`, `yaml`.
-   Multiple **I/O operations** backends: `file-system` *(read/write)*, `url` *(read-only)*, `s3` *(read/write)*.
-   Many **utility** and **parse methods** to retrieve data as needed *(check the [API](#api) section)*.
-   Well **tested**. ;)

## Index
-   [Installation](#installation)
    -   [Optional Requirements](#optional-requirements)
-   [Usage](#usage)
    -   [Basics](#basics)
    -   [Keyattr](#keyattr) `my_dict.x.y.z`
    -   [Keylist](#keylist) `my_dict["x", "y", "z"]`
    -   [Keypath](#keypath) `my_dict["x.y.z"]`
        -   [Custom keypath separator](#custom-keypath-separator)
        -   [Change keypath separator](#change-keypath-separator)
        -   [Disable keypath functionality](#disable-keypath-functionality)
        -   [List index support](#list-index-support)
    -   [I/O](#io)
    -   [API](#api)
        -   [Utility methods](#utility-methods)
        -   [I/O methods](#io-methods)
        -   [Parse methods](#parse-methods)
-   [Testing](#testing)
-   [License](#license)

## Installation
If you want to install **everything**:
-   Run `pip install "python-benedict[all]"`

alternatively you can install the main package:
-   Run `pip install python-benedict`, then install only the [optional requirements](#optional-requirements) you need.

### Optional Requirements
Here the hierarchy of possible installation targets available when running `pip install "python-benedict[...]"` *(each target installs all its sub-targets)*:
- `[all]`
    - `[io]`
        - `[html]`
        - `[toml]`
        - `[xls]`
        - `[xml]`
        - `[yaml]`
    - `[parse]`
    - `[s3]`

## Usage

### Basics
`benedict` is a `dict` subclass, so it is possible to use it as a normal dictionary *(you can just cast an existing dict)*.

```python
from benedict import benedict

# create a new empty instance
d = benedict()

# or cast an existing dict
d = benedict(existing_dict)

# or create from data source (filepath, url or data-string) in a supported format:
# Base64, CSV, JSON, TOML, XML, YAML, query-string
d = benedict("https://localhost:8000/data.json", format="json")

# or in a Django view
params = benedict(request.GET.items())
page = params.get_int("page", 1)
```

### Keyattr
It is possible to get/set items using **keys as attributes** (dotted notation).

```python
d = benedict(keyattr_dynamic=True) # default False
d.profile.firstname = "Fabio"
d.profile.lastname = "Caccamo"
print(d) # -> { "profile":{ "firstname":"Fabio", "lastname":"Caccamo" } }
```

By default, if the `keyattr_dynamic` is not explicitly set to `True`, this functionality works for get/set only already existing items.

#### Disable keyattr functionality
You can disable the keyattr functionality passing `keyattr_enabled=False` option in the constructor.

```python
d = benedict(existing_dict, keyattr_enabled=False) # default True
```

or using the `getter/setter` property.

```python
d.keyattr_enabled = False
```

#### Dynamic keyattr functionality
You can enable the dynamic attributes access functionality passing `keyattr_dynamic=True` in the constructor.

```python
d = benedict(existing_dict, keyattr_dynamic=True) # default False
```

or using the `getter/setter` property.

```python
d.keyattr_dynamic = True
```

> **Warning** - even if this feature is very useful, it has some obvious limitations: it works only for string keys that are *unprotected* (not starting with an `_`) and that don't clash with the currently supported methods names.

### Keylist
Wherever a **key** is used, it is possible to use also a **list (or a tuple) of keys**.

```python
d = benedict()

# set values by keys list
d["profile", "firstname"] = "Fabio"
d["profile", "lastname"] = "Caccamo"
print(d) # -> { "profile":{ "firstname":"Fabio", "lastname":"Caccamo" } }
print(d["profile"]) # -> { "firstname":"Fabio", "lastname":"Caccamo" }

# check if keypath exists in dict
print(["profile", "lastname"] in d) # -> True

# delete value by keys list
del d["profile", "lastname"]
print(d["profile"]) # -> { "firstname":"Fabio" }
```

### Keypath
`.` is the default keypath separator.

If you cast an existing dict and its keys contain the keypath separator a `ValueError` will be raised.

In this case you should use a [custom keypath separator](#custom-keypath-separator) or [disable keypath functionality](#disable-keypath-functionality).

```python
d = benedict()

# set values by keypath
d["profile.firstname"] = "Fabio"
d["profile.lastname"] = "Caccamo"
print(d) # -> { "profile":{ "firstname":"Fabio", "lastname":"Caccamo" } }
print(d["profile"]) # -> { "firstname":"Fabio", "lastname":"Caccamo" }

# check if keypath exists in dict
print("profile.lastname" in d) # -> True

# delete value by keypath
del d["profile.lastname"]
```

#### Custom keypath separator
You can customize the keypath separator passing the `keypath_separator` argument in the constructor.

If you pass an existing dict to the constructor and its keys contain the keypath separator an `Exception` will be raised.

```python
d = benedict(existing_dict, keypath_separator="/")
```

#### Change keypath separator
You can change the `keypath_separator` at any time using the `getter/setter` property.

If any existing key contains the new `keypath_separator` an `Exception` will be raised.

```python
d.keypath_separator = "/"
```

#### Disable keypath functionality
You can disable the keypath functionality passing `keypath_separator=None` option in the constructor.

```python
d = benedict(existing_dict, keypath_separator=None)
```

or using the `getter/setter` property.

```python
d.keypath_separator = None
```

#### List index support
List index are supported, keypaths can include indexes *(also negative)* using `[n]`, to perform any operation very fast:

```python
# Eg. get last location cordinates of the first result:
loc = d["results[0].locations[-1].coordinates"]
lat = loc.get_decimal("latitude")
lng = loc.get_decimal("longitude")
```

### I/O

For simplifying I/O operations, `benedict` supports a variety of input/output methods with most common formats: `base64`, `cli`, `csv`, `html`, `ini`, `json`, `pickle`, `plist`, `query-string`, `toml`, `xls`, `xml`, `yaml`.

#### Input via constructor

It is possible to create a `benedict` instance directly from data-source (`filepath`, `url`, `s3` or `data` string) by passing the data source and the data format (optional, default "json") in the constructor.

```python
# filepath
d = benedict("/root/data.yml", format="yaml")

# url
d = benedict("https://localhost:8000/data.xml", format="xml")

# s3
d = benedict("s3://my-bucket/data.xml", s3_options={"aws_access_key_id": "...", "aws_secret_access_key": "..."})

# data
d = benedict('{"a": 1, "b": 2, "c": 3, "x": 7, "y": 8, "z": 9}')
```

#### Input methods

- All *input* methods can be accessed as class methods and are prefixed by `from_*` followed by the format name.
- In all *input* methods, the first argument can represent a source: **file** path, **url**, **s3** url, or **data** string.

#### Input sources

All supported sources (**file**, **url**, **s3**, **data**) are allowed by default, but in certains situations when the input data comes from **untrusted sources** it may be useful to restrict the allowed sources using the `sources` argument:

```python
# url
d = benedict("https://localhost:8000/data.json", sources=["url"]) # -> ok
d = benedict.from_json("https://localhost:8000/data.json", sources=["url"]) # -> ok

# s3
d = benedict("s3://my-bucket/data.json", sources=["url"]) # -> raise ValueError
d = benedict.from_json("s3://my-bucket/data.json", sources=["url"]) # -> raise ValueError
```

#### Output methods

- All *output* methods can be accessed as instance methods and are prefixed by `to_*` followed by the format name.
- In all *output* methods, if `filepath="..."` kwarg is specified, the output will be also **saved** at the specified filepath.

#### Supported formats

Here are the details of the supported formats, operations and extra options docs.

| **format**     | **input**          | **output**         | **extra options docs**                                                                |
|----------------|--------------------|--------------------|---------------------------------------------------------------------------------------|
| `base64`       | :white_check_mark: | :white_check_mark: | -                                                                                     |
| `cli`          | :white_check_mark: | :x:                | [argparse](https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser)   |
| `csv`          | :white_check_mark: | :white_check_mark: | [csv](https://docs.python.org/3/library/csv.html)                                     |
| `html`         | :white_check_mark: | :x:                | [bs4](https://beautiful-soup-4.readthedocs.io) *(Beautiful Soup 4)*                   |
| `ini`          | :white_check_mark: | :white_check_mark: | [configparser](https://docs.python.org/3/library/configparser.html)                   |
| `json`         | :white_check_mark: | :white_check_mark: | [json](https://docs.python.org/3/library/json.html)                                   |
| `pickle`       | :white_check_mark: | :white_check_mark: | [pickle](https://docs.python.org/3/library/pickle.html)                               |
| `plist`        | :white_check_mark: | :white_check_mark: | [plistlib](https://docs.python.org/3/library/plistlib.html)                           |
| `query-string` | :white_check_mark: | :white_check_mark: | -                                                                                     |
| `toml`         | :white_check_mark: | :white_check_mark: | [toml](https://pypi.org/project/toml/)                                                |
| `xls`          | :white_check_mark: | :x:                | [openpyxl](https://openpyxl.readthedocs.io/) - [xlrd](https://pypi.org/project/xlrd/) |
| `xml`          | :white_check_mark: | :white_check_mark: | [xmltodict](https://github.com/martinblech/xmltodict)                                 |
| `yaml`         | :white_check_mark: | :white_check_mark: | [PyYAML](https://pyyaml.org/wiki/PyYAMLDocumentation)                                 |

### API

-   **Utility methods**

    -   [`clean`](#clean)
    -   [`clone`](#clone)
    -   [`dump`](#dump)
    -   [`filter`](#filter)
    -   [`find`](#find)
    -   [`flatten`](#flatten)
    -   [`groupby`](#groupby)
    -   [`invert`](#invert)
    -   [`items_sorted_by_keys`](#items_sorted_by_keys)
    -   [`items_sorted_by_values`](#items_sorted_by_values)
    -   [`keypaths`](#keypaths)
    -   [`match`](#match)
    -   [`merge`](#merge)
    -   [`move`](#move)
    -   [`nest`](#nest)
    -   [`remove`](#remove)
    -   [`rename`](#rename)
    -   [`search`](#search)
    -   [`standardize`](#standardize)
    -   [`subset`](#subset)
    -   [`swap`](#swap)
    -   [`traverse`](#traverse)
    -   [`unflatten`](#unflatten)
    -   [`unique`](#unique)

-   **I/O methods**

    -   [`from_base64`](#from_base64)
    -   [`from_cli`](#from_cli)
    -   [`from_csv`](#from_csv)
    -   [`from_ini`](#from_ini)
    -   [`from_html`](#from_html)
    -   [`from_json`](#from_json)
    -   [`from_pickle`](#from_pickle)
    -   [`from_plist`](#from_plist)
    -   [`from_query_string`](#from_query_string)
    -   [`from_toml`](#from_toml)
    -   [`from_xls`](#from_xls)
    -   [`from_xml`](#from_xml)
    -   [`from_yaml`](#from_yaml)
    -   [`to_base64`](#to_base64)
    -   [`to_csv`](#to_csv)
    -   [`to_ini`](#to_ini)
    -   [`to_json`](#to_json)
    -   [`to_pickle`](#to_pickle)
    -   [`to_plist`](#to_plist)
    -   [`to_query_string`](#to_query_string)
    -   [`to_toml`](#to_toml)
    -   [`to_xml`](#to_xml)
    -   [`to_yaml`](#to_yaml)

-   **Parse methods**

    -   [`get_bool`](#get_bool)
    -   [`get_bool_list`](#get_bool_list)
    -   [`get_date`](#get_date)
    -   [`get_date_list`](#get_date_list)
    -   [`get_datetime`](#get_datetime)
    -   [`get_datetime_list`](#get_datetime_list)
    -   [`get_decimal`](#get_decimal)
    -   [`get_decimal_list`](#get_decimal_list)
    -   [`get_dict`](#get_dict)
    -   [`get_email`](#get_email)
    -   [`get_float`](#get_float)
    -   [`get_float_list`](#get_float_list)
    -   [`get_int`](#get_int)
    -   [`get_int_list`](#get_int_list)
    -   [`get_list`](#get_list)
    -   [`get_list_item`](#get_list_item)
    -   [`get_phonenumber`](#get_phonenumber)
    -   [`get_slug`](#get_slug)
    -   [`get_slug_list`](#get_slug_list)
    -   [`get_str`](#get_str)
    -   [`get_str_list`](#get_str_list)
    -   [`get_uuid`](#get_uuid)
    -   [`get_uuid_list`](#get_uuid_list)

### Utility methods

These methods are common utilities that will speed up your everyday work.

Utilities that accept key argument(s) also support keypath(s).

Utilities that return a dictionary always return a new `benedict` instance.

#### `clean`

```python
# Clean the current dict instance removing all empty values: None, "", {}, [], ().
# If strings or collections (dict, list, set, tuple) flags are False,
# related empty values will not be deleted.
d.clean(strings=True, collections=True)
```

#### `clone`

```python
# Return a clone (deepcopy) of the dict.
c = d.clone()
```

#### `dump`

```python
# Return a readable representation of any dict/list.
# This method can be used both as static method or instance method.
s = benedict.dump(d.keypaths())
print(s)
# or
d = benedict()
print(d.dump())
```

#### `filter`

```python
# Return a filtered dict using the given predicate function.
# Predicate function receives key, value arguments and should return a bool value.
predicate = lambda k, v: v is not None
f = d.filter(predicate)
```

#### `find`

```python
# Return the first match searching for the given keys/keypaths.
# If no result found, default value is returned.
keys = ["a.b.c", "m.n.o", "x.y.z"]
f = d.find(keys, default=0)
```

#### `flatten`

```python
# Return a new flattened dict using the given separator to join nested dict keys to flatten keypaths.
f = d.flatten(separator="_")
```

#### `groupby`

```python
# Group a list of dicts at key by the value of the given by_key and return a new dict.
g = d.groupby("cities", by_key="country_code")
```

#### `invert`

```python
# Return an inverted dict where values become keys and keys become values.
# Since multiple keys could have the same value, each value will be a list of keys.
# If flat is True each value will be a single value (use this only if values are unique).
i = d.invert(flat=False)
```

#### `items_sorted_by_keys`

```python
# Return items (key/value list) sorted by keys.
# If reverse is True, the list will be reversed.
items = d.items_sorted_by_keys(reverse=False)
```

#### `items_sorted_by_values`

```python
# Return items (key/value list) sorted by values.
# If reverse is True, the list will be reversed.
items = d.items_sorted_by_values(reverse=False)
```

#### `keypaths`

```python
# Return a list of all keypaths in the dict.
# If indexes is True, the output will include list values indexes.
k = d.keypaths(indexes=False)
```

#### `match`

```python
# Return a list of all values whose keypath matches the given pattern (a regex or string).
# If pattern is string, wildcard can be used (eg. [*] can be used to match all list indexes).
# If indexes is True, the pattern will be matched also against list values.
m = d.match(pattern, indexes=True)
```

#### `merge`

```python
# Merge one or more dictionary objects into current instance (deepupdate).
# Sub-dictionaries keys will be merged together.
# If overwrite is False, existing values will not be overwritten.
# If concat is True, list values will be concatenated together.
d.merge(a, b, c, overwrite=True, concat=False)
```

#### `move`

```python
# Move an item from key_src to key_dst.
# It can be used to rename a key.
# If key_dst exists, its value will be overwritten.
d.move("a", "b", overwrite=True)
```

#### `nest`

```python
# Nest a list of dicts at the given key and return a new nested list
# using the specified keys to establish the correct items hierarchy.
d.nest("values", id_key="id", parent_id_key="parent_id", children_key="children")
```

#### `remove`

```python
# Remove multiple keys from the dict.
# It is possible to pass a single key or more keys (as list or *args).
d.remove(["firstname", "lastname", "email"])
```

#### `rename`

```python
# Rename a dict item key from "key" to "key_new".
# If key_new exists, a KeyError will be raised.
d.rename("first_name", "firstname")
```

#### `search`

```python
# Search and return a list of items (dict, key, value, ) matching the given query.
r = d.search("hello", in_keys=True, in_values=True, exact=False, case_sensitive=False)
```

#### `standardize`

```python
# Standardize all dict keys, e.g. "Location Latitude" -> "location_latitude".
d.standardize()
```

#### `subset`

```python
# Return a dict subset for the given keys.
# It is possible to pass a single key or more keys (as list or *args).
s = d.subset(["firstname", "lastname", "email"])
```

#### `swap`

```python
# Swap items values at the given keys.
d.swap("firstname", "lastname")
```

#### `traverse`

```python
# Traverse a dict passing each item (dict, key, value) to the given callback function.
def f(d, key, value):
    print(f"dict: {d} - key: {key} - value: {value}")
d.traverse(f)
```

#### `unflatten`

```python
# Return a new unflattened dict using the given separator to split dict keys to nested keypaths.
u = d.unflatten(separator="_")
```

#### `unique`

```python
# Remove duplicated values from the dict.
d.unique()
```

### I/O methods

These methods are available for input/output operations.

#### `from_base64`

```python
# Try to load/decode a base64 encoded data and return it as benedict instance.
# Accept as first argument: url, filepath or data-string.
# It's possible to choose the subformat used under the hood:
# ('csv', 'json', 'query-string', 'toml', 'xml', 'yaml'), default: 'json'.
# It's possible to choose the encoding, default 'utf-8'.
# A ValueError is raised in case of failure.
d = benedict.from_base64(s, subformat="json", encoding="utf-8", **kwargs)
```

#### `from_cli`

```python
# Load and decode data from a string of CLI arguments.
# ArgumentParser specific options can be passed using kwargs:
# https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser
# Return a new dict instance. A ValueError is raised in case of failure.
d = benedict.from_cli(s, **kwargs)
```

#### `from_csv`

```python
# Try to load/decode a csv encoded data and return it as benedict instance.
# Accept as first argument: url, filepath or data-string.
# It's possible to specify the columns list, default: None (in this case the first row values will be used as keys).
# It's possible to pass decoder specific options using kwargs:
# https://docs.python.org/3/library/csv.html
# A ValueError is raised in case of failure.
d = benedict.from_csv(s, columns=None, columns_row=True, **kwargs)
```

#### `from_html`

```python
# Try to load/decode a html data and return it as benedict instance.
# Accept as first argument: url, filepath or data-string.
# It's possible to pass decoder specific options using kwargs:
# https://beautiful-soup-4.readthedocs.io/
# A ValueError is raised in case of failure.
d = benedict.from_html(s, **kwargs)
```

#### `from_ini`

```python
# Try to load/decode a ini encoded data and return it as benedict instance.
# Accept as first argument: url, filepath or data-string.
# It's possible to pass decoder specific options using kwargs:
# https://docs.python.org/3/library/configparser.html
# A ValueError is raised in case of failure.
d = benedict.from_ini(s, **kwargs)
```

#### `from_json`

```python
# Try to load/decode a json encoded data and return it as benedict instance.
# Accept as first argument: url, filepath or data-string.
# It's possible to pass decoder specific options using kwargs:
# https://docs.python.org/3/library/json.html
# A ValueError is raised in case of failure.
d = benedict.from_json(s, **kwargs)
```

#### `from_pickle`

```python
# Try to load/decode a pickle encoded in Base64 format and return it as benedict instance.
# Accept as first argument: url, filepath or data-string.
# It's possible to pass decoder specific options using kwargs:
# https://docs.python.org/3/library/pickle.html
# A ValueError is raised in case of failure.
d = benedict.from_pickle(s, **kwargs)
```

#### `from_plist`

```python
# Try to load/decode a p-list encoded data and return it as benedict instance.
# Accept as first argument: url, filepath or data-string.
# It's possible to pass decoder specific options using kwargs:
# https://docs.python.org/3/library/plistlib.html
# A ValueError is raised in case of failure.
d = benedict.from_plist(s, **kwargs)
```

#### `from_query_string`

```python
# Try to load/decode a query-string and return it as benedict instance.
# Accept as first argument: url, filepath or data-string.
# A ValueError is raised in case of failure.
d = benedict.from_query_string(s, **kwargs)
```

#### `from_toml`

```python
# Try to load/decode a toml encoded data and return it as benedict instance.
# Accept as first argument: url, filepath or data-string.
# It's possible to pass decoder specific options using kwargs:
# https://pypi.org/project/toml/
# A ValueError is raised in case of failure.
d = benedict.from_toml(s, **kwargs)
```

#### `from_xls`

```python
# Try to load/decode a xls file (".xls", ".xlsx", ".xlsm") from url, filepath or data-string.
# Accept as first argument: url, filepath or data-string.
# It's possible to pass decoder specific options using kwargs:
# - https://openpyxl.readthedocs.io/ (for .xlsx and .xlsm files)
# - https://pypi.org/project/xlrd/ (for .xls files)
# A ValueError is raised in case of failure.
d = benedict.from_xls(s, sheet=0, columns=None, columns_row=True, **kwargs)
```

#### `from_xml`

```python
# Try to load/decode a xml encoded data and return it as benedict instance.
# Accept as first argument: url, filepath or data-string.
# It's possible to pass decoder specific options using kwargs:
# https://github.com/martinblech/xmltodict
# A ValueError is raised in case of failure.
d = benedict.from_xml(s, **kwargs)
```

#### `from_yaml`

```python
# Try to load/decode a yaml encoded data and return it as benedict instance.
# Accept as first argument: url, filepath or data-string.
# It's possible to pass decoder specific options using kwargs:
# https://pyyaml.org/wiki/PyYAMLDocumentation
# A ValueError is raised in case of failure.
d = benedict.from_yaml(s, **kwargs)
```

#### `to_base64`

```python
# Return the dict instance encoded in base64 format and optionally save it at the specified 'filepath'.
# It's possible to choose the subformat used under the hood:
# ('csv', json', 'query-string', 'toml', 'xml', 'yaml'), default: 'json'.
# It's possible to choose the encoding, default 'utf-8'.
# It's possible to pass decoder specific options using kwargs.
# A ValueError is raised in case of failure.
s = d.to_base64(subformat="json", encoding="utf-8", **kwargs)
```

#### `to_csv`

```python
# Return a list of dicts in the current dict encoded in csv format and optionally save it at the specified filepath.
# It's possible to specify the key of the item (list of dicts) to encode, default: 'values'.
# It's possible to specify the columns list, default: None (in this case the keys of the first item will be used).
# A ValueError is raised in case of failure.
s = d.to_csv(key="values", columns=None, columns_row=True, **kwargs)
```

#### `to_ini`

```python
# Return the dict instance encoded in ini format and optionally save it at the specified filepath.
# It's possible to pass encoder specific options using kwargs:
# https://docs.python.org/3/library/configparser.html
# A ValueError is raised in case of failure.
s = d.to_ini(**kwargs)
```

#### `to_json`

```python
# Return the dict instance encoded in json format and optionally save it at the specified filepath.
# It's possible to pass encoder specific options using kwargs:
# https://docs.python.org/3/library/json.html
# A ValueError is raised in case of failure.
s = d.to_json(**kwargs)
```

#### `to_pickle`

```python
# Return the dict instance as pickle encoded in Base64 format and optionally save it at the specified filepath.
# The pickle protocol used by default is 2.
# It's possible to pass encoder specific options using kwargs:
# https://docs.python.org/3/library/pickle.html
# A ValueError is raised in case of failure.
s = d.to_pickle(**kwargs)
```

#### `to_plist`

```python
# Return the dict instance encoded in p-list format and optionally save it at the specified filepath.
# It's possible to pass encoder specific options using kwargs:
# https://docs.python.org/3/library/plistlib.html
# A ValueError is raised in case of failure.
s = d.to_plist(**kwargs)
```

#### `to_query_string`

```python
# Return the dict instance as query-string and optionally save it at the specified filepath.
# A ValueError is raised in case of failure.
s = d.to_query_string(**kwargs)
```

#### `to_toml`

```python
# Return the dict instance encoded in toml format and optionally save it at the specified filepath.
# It's possible to pass encoder specific options using kwargs:
# https://pypi.org/project/toml/
# A ValueError is raised in case of failure.
s = d.to_toml(**kwargs)
```

#### `to_xml`

```python
# Return the dict instance encoded in xml format and optionally save it at the specified filepath.
# It's possible to pass encoder specific options using kwargs:
# https://github.com/martinblech/xmltodict
# A ValueError is raised in case of failure.
s = d.to_xml(**kwargs)
```

#### `to_yaml`

```python
# Return the dict instance encoded in yaml format.
# If filepath option is passed the output will be saved ath
# It's possible to pass encoder specific options using kwargs:
# https://pyyaml.org/wiki/PyYAMLDocumentation
# A ValueError is raised in case of failure.
s = d.to_yaml(**kwargs)
```

### Parse methods

These methods are wrappers of the `get` method, they parse data trying to return it in the expected type.

#### `get_bool`

```python
# Get value by key or keypath trying to return it as bool.
# Values like `1`, `true`, `yes`, `on`, `ok` will be returned as `True`.
d.get_bool(key, default=False)
```

#### `get_bool_list`

```python
# Get value by key or keypath trying to return it as list of bool values.
# If separator is specified and value is a string it will be splitted.
d.get_bool_list(key, default=[], separator=",")
```

#### `get_date`

```python
# Get value by key or keypath trying to return it as date.
# If format is not specified it will be autodetected.
# If choices and value is in choices return value otherwise default.
d.get_date(key, default=None, format=None, choices=[])
```

#### `get_date_list`

```python
# Get value by key or keypath trying to return it as list of date values.
# If separator is specified and value is a string it will be splitted.
d.get_date_list(key, default=[], format=None, separator=",")
```

#### `get_datetime`

```python
# Get value by key or keypath trying to return it as datetime.
# If format is not specified it will be autodetected.
# If choices and value is in choices return value otherwise default.
d.get_datetime(key, default=None, format=None, choices=[])
```

#### `get_datetime_list`

```python
# Get value by key or keypath trying to return it as list of datetime values.
# If separator is specified and value is a string it will be splitted.
d.get_datetime_list(key, default=[], format=None, separator=",")
```

#### `get_decimal`

```python
# Get value by key or keypath trying to return it as Decimal.
# If choices and value is in choices return value otherwise default.
d.get_decimal(key, default=Decimal("0.0"), choices=[])
```

#### `get_decimal_list`

```python
# Get value by key or keypath trying to return it as list of Decimal values.
# If separator is specified and value is a string it will be splitted.
d.get_decimal_list(key, default=[], separator=",")
```

#### `get_dict`

```python
# Get value by key or keypath trying to return it as dict.
# If value is a json string it will be automatically decoded.
d.get_dict(key, default={})
```

#### `get_email`

```python
# Get email by key or keypath and return it.
# If value is blacklisted it will be automatically ignored.
# If check_blacklist is False, it will be not ignored even if blacklisted.
d.get_email(key, default="", choices=None, check_blacklist=True)
```

#### `get_float`

```python
# Get value by key or keypath trying to return it as float.
# If choices and value is in choices return value otherwise default.
d.get_float(key, default=0.0, choices=[])
```

#### `get_float_list`

```python
# Get value by key or keypath trying to return it as list of float values.
# If separator is specified and value is a string it will be splitted.
d.get_float_list(key, default=[], separator=",")
```

#### `get_int`

```python
# Get value by key or keypath trying to return it as int.
# If choices and value is in choices return value otherwise default.
d.get_int(key, default=0, choices=[])
```

#### `get_int_list`

```python
# Get value by key or keypath trying to return it as list of int values.
# If separator is specified and value is a string it will be splitted.
d.get_int_list(key, default=[], separator=",")
```

#### `get_list`

```python
# Get value by key or keypath trying to return it as list.
# If separator is specified and value is a string it will be splitted.
d.get_list(key, default=[], separator=",")
```

#### `get_list_item`

```python
# Get list by key or keypath and return value at the specified index.
# If separator is specified and list value is a string it will be splitted.
d.get_list_item(key, index=0, default=None, separator=",")
```

#### `get_phonenumber`

```python
# Get phone number by key or keypath and return a dict with different formats (e164, international, national).
# If country code is specified (alpha 2 code), it will be used to parse phone number correctly.
d.get_phonenumber(key, country_code=None, default=None)
```

#### `get_slug`

```python
# Get value by key or keypath trying to return it as slug.
# If choices and value is in choices return value otherwise default.
d.get_slug(key, default="", choices=[])
```

#### `get_slug_list`

```python
# Get value by key or keypath trying to return it as list of slug values.
# If separator is specified and value is a string it will be splitted.
d.get_slug_list(key, default=[], separator=",")
```

#### `get_str`

```python
# Get value by key or keypath trying to return it as string.
# Encoding issues will be automatically fixed.
# If choices and value is in choices return value otherwise default.
d.get_str(key, default="", choices=[])
```

#### `get_str_list`

```python
# Get value by key or keypath trying to return it as list of str values.
# If separator is specified and value is a string it will be splitted.
d.get_str_list(key, default=[], separator=",")
```

#### `get_uuid`

```python
# Get value by key or keypath trying to return it as valid uuid.
# If choices and value is in choices return value otherwise default.
d.get_uuid(key, default="", choices=[])
```

#### `get_uuid_list`

```python
# Get value by key or keypath trying to return it as list of valid uuid values.
# If separator is specified and value is a string it will be splitted.
d.get_uuid_list(key, default=[], separator=",")
```

## Testing
```bash
# clone repository
git clone https://github.com/fabiocaccamo/python-benedict.git && cd python-benedict

# create virtualenv and activate it
python -m venv venv && . venv/bin/activate

# upgrade pip
python -m pip install --upgrade pip

# install requirements
pip install -r requirements.txt -r requirements-test.txt

# install pre-commit to run formatters and linters
pre-commit install --install-hooks

# run tests using tox
tox

# or run tests using unittest
python -m unittest
```

## License
Released under [MIT License](LICENSE.txt).

---

## Supporting

- :star: Star this project on [GitHub](https://github.com/fabiocaccamo/python-benedict)
- :octocat: Follow me on [GitHub](https://github.com/fabiocaccamo)
- :blue_heart: Follow me on [Twitter](https://twitter.com/fabiocaccamo)
- :moneybag: Sponsor me on [Github](https://github.com/sponsors/fabiocaccamo)

## See also

- [`python-fontbro`](https://github.com/fabiocaccamo/python-fontbro) - 🧢 friendly font operations on top of `fontTools`.

- [`python-fsutil`](https://github.com/fabiocaccamo/python-fsutil) - 🧟‍♂️ high-level file-system operations for lazy devs.

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "python-benedict",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "Fabio Caccamo <fabio.caccamo@gmail.com>",
    "keywords": "python,dictionary,dictionaries,dict,benedict,subclass,extended,keylist,keypath,utility,io,data,file,url,read,write,parse,configparser,config,cfg,pickle,plist,base64,csv,html,ini,json,query-string,toml,xml,yaml,clean,clone,deepclone,deepupdate,dump,filter,flatten,groupby,invert,merge,move,nest,remove,rename,search,standardize,subset,swap,traverse,unflatten,unique",
    "author": "",
    "author_email": "Fabio Caccamo <fabio.caccamo@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/57/63/a3d1de78d75b28e9105c236565b9f0366e009abb489a5acb09911fcf5768/python-benedict-0.33.2.tar.gz",
    "platform": null,
    "description": "[![](https://img.shields.io/pypi/pyversions/python-benedict.svg?color=blue&logo=python&logoColor=white)](https://www.python.org/)\n[![](https://img.shields.io/pypi/v/python-benedict.svg?color=blue&logo=pypi&logoColor=white)](https://pypi.org/project/python-benedict/)\n[![](https://static.pepy.tech/badge/python-benedict/month)](https://pepy.tech/project/python-benedict)\n[![](https://img.shields.io/github/stars/fabiocaccamo/python-benedict?logo=github&style=flat)](https://github.com/fabiocaccamo/python-benedict/stargazers)\n[![](https://img.shields.io/pypi/l/python-benedict.svg?color=blue)](https://github.com/fabiocaccamo/python-benedict/blob/main/LICENSE.txt)\n\n[![](https://results.pre-commit.ci/badge/github/fabiocaccamo/python-benedict/main.svg)](https://results.pre-commit.ci/latest/github/fabiocaccamo/python-benedict/main)\n[![](https://img.shields.io/github/actions/workflow/status/fabiocaccamo/python-benedict/test-package.yml?branch=main&label=build&logo=github)](https://github.com/fabiocaccamo/python-benedict)\n[![](https://img.shields.io/codecov/c/gh/fabiocaccamo/python-benedict?logo=codecov)](https://codecov.io/gh/fabiocaccamo/python-benedict)\n[![](https://img.shields.io/codeclimate/maintainability/fabiocaccamo/python-benedict?logo=code-climate)](https://codeclimate.com/github/fabiocaccamo/python-benedict/)\n[![](https://img.shields.io/codacy/grade/0dbd5cc2089f4dce80a0e49e6822be3c?logo=codacy)](https://www.codacy.com/app/fabiocaccamo/python-benedict)\n[![](https://img.shields.io/scrutinizer/quality/g/fabiocaccamo/python-benedict?logo=scrutinizer)](https://scrutinizer-ci.com/g/fabiocaccamo/python-benedict/?branch=main)\n[![](https://img.shields.io/badge/code%20style-black-000000.svg?logo=python&logoColor=black)](https://github.com/psf/black)\n[![](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)\n\n# python-benedict\npython-benedict is a dict subclass with **keylist/keypath/keyattr** support, **I/O** shortcuts (`base64`, `cli`, `csv`, `html`, `ini`, `json`, `pickle`, `plist`, `query-string`, `toml`, `xls`, `xml`, `yaml`) and many **utilities**... for humans, obviously.\n\n## Features\n-   100% **backward-compatible**, you can safely wrap existing dictionaries.\n-   `NEW` **Keyattr** support for get/set items using **keys as attributes**.\n-   **Keylist** support using **list of keys** as key.\n-   **Keypath** support using **keypath-separator** *(dot syntax by default)*.\n-   Keypath **list-index** support  *(also negative)* using the standard `[n]` suffix.\n-   Normalized **I/O operations** with most common formats: `base64`, `cli`, `csv`, `html`, `ini`, `json`, `pickle`, `plist`, `query-string`, `toml`, `xls`, `xml`, `yaml`.\n-   Multiple **I/O operations** backends: `file-system` *(read/write)*, `url` *(read-only)*, `s3` *(read/write)*.\n-   Many **utility** and **parse methods** to retrieve data as needed *(check the [API](#api) section)*.\n-   Well **tested**. ;)\n\n## Index\n-   [Installation](#installation)\n    -   [Optional Requirements](#optional-requirements)\n-   [Usage](#usage)\n    -   [Basics](#basics)\n    -   [Keyattr](#keyattr) `my_dict.x.y.z`\n    -   [Keylist](#keylist) `my_dict[\"x\", \"y\", \"z\"]`\n    -   [Keypath](#keypath) `my_dict[\"x.y.z\"]`\n        -   [Custom keypath separator](#custom-keypath-separator)\n        -   [Change keypath separator](#change-keypath-separator)\n        -   [Disable keypath functionality](#disable-keypath-functionality)\n        -   [List index support](#list-index-support)\n    -   [I/O](#io)\n    -   [API](#api)\n        -   [Utility methods](#utility-methods)\n        -   [I/O methods](#io-methods)\n        -   [Parse methods](#parse-methods)\n-   [Testing](#testing)\n-   [License](#license)\n\n## Installation\nIf you want to install **everything**:\n-   Run `pip install \"python-benedict[all]\"`\n\nalternatively you can install the main package:\n-   Run `pip install python-benedict`, then install only the [optional requirements](#optional-requirements) you need.\n\n### Optional Requirements\nHere the hierarchy of possible installation targets available when running `pip install \"python-benedict[...]\"` *(each target installs all its sub-targets)*:\n- `[all]`\n    - `[io]`\n        - `[html]`\n        - `[toml]`\n        - `[xls]`\n        - `[xml]`\n        - `[yaml]`\n    - `[parse]`\n    - `[s3]`\n\n## Usage\n\n### Basics\n`benedict` is a `dict` subclass, so it is possible to use it as a normal dictionary *(you can just cast an existing dict)*.\n\n```python\nfrom benedict import benedict\n\n# create a new empty instance\nd = benedict()\n\n# or cast an existing dict\nd = benedict(existing_dict)\n\n# or create from data source (filepath, url or data-string) in a supported format:\n# Base64, CSV, JSON, TOML, XML, YAML, query-string\nd = benedict(\"https://localhost:8000/data.json\", format=\"json\")\n\n# or in a Django view\nparams = benedict(request.GET.items())\npage = params.get_int(\"page\", 1)\n```\n\n### Keyattr\nIt is possible to get/set items using **keys as attributes** (dotted notation).\n\n```python\nd = benedict(keyattr_dynamic=True) # default False\nd.profile.firstname = \"Fabio\"\nd.profile.lastname = \"Caccamo\"\nprint(d) # -> { \"profile\":{ \"firstname\":\"Fabio\", \"lastname\":\"Caccamo\" } }\n```\n\nBy default, if the `keyattr_dynamic` is not explicitly set to `True`, this functionality works for get/set only already existing items.\n\n#### Disable keyattr functionality\nYou can disable the keyattr functionality passing `keyattr_enabled=False` option in the constructor.\n\n```python\nd = benedict(existing_dict, keyattr_enabled=False) # default True\n```\n\nor using the `getter/setter` property.\n\n```python\nd.keyattr_enabled = False\n```\n\n#### Dynamic keyattr functionality\nYou can enable the dynamic attributes access functionality passing `keyattr_dynamic=True` in the constructor.\n\n```python\nd = benedict(existing_dict, keyattr_dynamic=True) # default False\n```\n\nor using the `getter/setter` property.\n\n```python\nd.keyattr_dynamic = True\n```\n\n> **Warning** - even if this feature is very useful, it has some obvious limitations: it works only for string keys that are *unprotected* (not starting with an `_`) and that don't clash with the currently supported methods names.\n\n### Keylist\nWherever a **key** is used, it is possible to use also a **list (or a tuple) of keys**.\n\n```python\nd = benedict()\n\n# set values by keys list\nd[\"profile\", \"firstname\"] = \"Fabio\"\nd[\"profile\", \"lastname\"] = \"Caccamo\"\nprint(d) # -> { \"profile\":{ \"firstname\":\"Fabio\", \"lastname\":\"Caccamo\" } }\nprint(d[\"profile\"]) # -> { \"firstname\":\"Fabio\", \"lastname\":\"Caccamo\" }\n\n# check if keypath exists in dict\nprint([\"profile\", \"lastname\"] in d) # -> True\n\n# delete value by keys list\ndel d[\"profile\", \"lastname\"]\nprint(d[\"profile\"]) # -> { \"firstname\":\"Fabio\" }\n```\n\n### Keypath\n`.` is the default keypath separator.\n\nIf you cast an existing dict and its keys contain the keypath separator a `ValueError` will be raised.\n\nIn this case you should use a [custom keypath separator](#custom-keypath-separator) or [disable keypath functionality](#disable-keypath-functionality).\n\n```python\nd = benedict()\n\n# set values by keypath\nd[\"profile.firstname\"] = \"Fabio\"\nd[\"profile.lastname\"] = \"Caccamo\"\nprint(d) # -> { \"profile\":{ \"firstname\":\"Fabio\", \"lastname\":\"Caccamo\" } }\nprint(d[\"profile\"]) # -> { \"firstname\":\"Fabio\", \"lastname\":\"Caccamo\" }\n\n# check if keypath exists in dict\nprint(\"profile.lastname\" in d) # -> True\n\n# delete value by keypath\ndel d[\"profile.lastname\"]\n```\n\n#### Custom keypath separator\nYou can customize the keypath separator passing the `keypath_separator` argument in the constructor.\n\nIf you pass an existing dict to the constructor and its keys contain the keypath separator an `Exception` will be raised.\n\n```python\nd = benedict(existing_dict, keypath_separator=\"/\")\n```\n\n#### Change keypath separator\nYou can change the `keypath_separator` at any time using the `getter/setter` property.\n\nIf any existing key contains the new `keypath_separator` an `Exception` will be raised.\n\n```python\nd.keypath_separator = \"/\"\n```\n\n#### Disable keypath functionality\nYou can disable the keypath functionality passing `keypath_separator=None` option in the constructor.\n\n```python\nd = benedict(existing_dict, keypath_separator=None)\n```\n\nor using the `getter/setter` property.\n\n```python\nd.keypath_separator = None\n```\n\n#### List index support\nList index are supported, keypaths can include indexes *(also negative)* using `[n]`, to perform any operation very fast:\n\n```python\n# Eg. get last location cordinates of the first result:\nloc = d[\"results[0].locations[-1].coordinates\"]\nlat = loc.get_decimal(\"latitude\")\nlng = loc.get_decimal(\"longitude\")\n```\n\n### I/O\n\nFor simplifying I/O operations, `benedict` supports a variety of input/output methods with most common formats: `base64`, `cli`, `csv`, `html`, `ini`, `json`, `pickle`, `plist`, `query-string`, `toml`, `xls`, `xml`, `yaml`.\n\n#### Input via constructor\n\nIt is possible to create a `benedict` instance directly from data-source (`filepath`, `url`, `s3` or `data` string) by passing the data source and the data format (optional, default \"json\") in the constructor.\n\n```python\n# filepath\nd = benedict(\"/root/data.yml\", format=\"yaml\")\n\n# url\nd = benedict(\"https://localhost:8000/data.xml\", format=\"xml\")\n\n# s3\nd = benedict(\"s3://my-bucket/data.xml\", s3_options={\"aws_access_key_id\": \"...\", \"aws_secret_access_key\": \"...\"})\n\n# data\nd = benedict('{\"a\": 1, \"b\": 2, \"c\": 3, \"x\": 7, \"y\": 8, \"z\": 9}')\n```\n\n#### Input methods\n\n- All *input* methods can be accessed as class methods and are prefixed by `from_*` followed by the format name.\n- In all *input* methods, the first argument can represent a source: **file** path, **url**, **s3** url, or **data** string.\n\n#### Input sources\n\nAll supported sources (**file**, **url**, **s3**, **data**) are allowed by default, but in certains situations when the input data comes from **untrusted sources** it may be useful to restrict the allowed sources using the `sources` argument:\n\n```python\n# url\nd = benedict(\"https://localhost:8000/data.json\", sources=[\"url\"]) # -> ok\nd = benedict.from_json(\"https://localhost:8000/data.json\", sources=[\"url\"]) # -> ok\n\n# s3\nd = benedict(\"s3://my-bucket/data.json\", sources=[\"url\"]) # -> raise ValueError\nd = benedict.from_json(\"s3://my-bucket/data.json\", sources=[\"url\"]) # -> raise ValueError\n```\n\n#### Output methods\n\n- All *output* methods can be accessed as instance methods and are prefixed by `to_*` followed by the format name.\n- In all *output* methods, if `filepath=\"...\"` kwarg is specified, the output will be also **saved** at the specified filepath.\n\n#### Supported formats\n\nHere are the details of the supported formats, operations and extra options docs.\n\n| **format**     | **input**          | **output**         | **extra options docs**                                                                |\n|----------------|--------------------|--------------------|---------------------------------------------------------------------------------------|\n| `base64`       | :white_check_mark: | :white_check_mark: | -                                                                                     |\n| `cli`          | :white_check_mark: | :x:                | [argparse](https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser)   |\n| `csv`          | :white_check_mark: | :white_check_mark: | [csv](https://docs.python.org/3/library/csv.html)                                     |\n| `html`         | :white_check_mark: | :x:                | [bs4](https://beautiful-soup-4.readthedocs.io) *(Beautiful Soup 4)*                   |\n| `ini`          | :white_check_mark: | :white_check_mark: | [configparser](https://docs.python.org/3/library/configparser.html)                   |\n| `json`         | :white_check_mark: | :white_check_mark: | [json](https://docs.python.org/3/library/json.html)                                   |\n| `pickle`       | :white_check_mark: | :white_check_mark: | [pickle](https://docs.python.org/3/library/pickle.html)                               |\n| `plist`        | :white_check_mark: | :white_check_mark: | [plistlib](https://docs.python.org/3/library/plistlib.html)                           |\n| `query-string` | :white_check_mark: | :white_check_mark: | -                                                                                     |\n| `toml`         | :white_check_mark: | :white_check_mark: | [toml](https://pypi.org/project/toml/)                                                |\n| `xls`          | :white_check_mark: | :x:                | [openpyxl](https://openpyxl.readthedocs.io/) - [xlrd](https://pypi.org/project/xlrd/) |\n| `xml`          | :white_check_mark: | :white_check_mark: | [xmltodict](https://github.com/martinblech/xmltodict)                                 |\n| `yaml`         | :white_check_mark: | :white_check_mark: | [PyYAML](https://pyyaml.org/wiki/PyYAMLDocumentation)                                 |\n\n### API\n\n-   **Utility methods**\n\n    -   [`clean`](#clean)\n    -   [`clone`](#clone)\n    -   [`dump`](#dump)\n    -   [`filter`](#filter)\n    -   [`find`](#find)\n    -   [`flatten`](#flatten)\n    -   [`groupby`](#groupby)\n    -   [`invert`](#invert)\n    -   [`items_sorted_by_keys`](#items_sorted_by_keys)\n    -   [`items_sorted_by_values`](#items_sorted_by_values)\n    -   [`keypaths`](#keypaths)\n    -   [`match`](#match)\n    -   [`merge`](#merge)\n    -   [`move`](#move)\n    -   [`nest`](#nest)\n    -   [`remove`](#remove)\n    -   [`rename`](#rename)\n    -   [`search`](#search)\n    -   [`standardize`](#standardize)\n    -   [`subset`](#subset)\n    -   [`swap`](#swap)\n    -   [`traverse`](#traverse)\n    -   [`unflatten`](#unflatten)\n    -   [`unique`](#unique)\n\n-   **I/O methods**\n\n    -   [`from_base64`](#from_base64)\n    -   [`from_cli`](#from_cli)\n    -   [`from_csv`](#from_csv)\n    -   [`from_ini`](#from_ini)\n    -   [`from_html`](#from_html)\n    -   [`from_json`](#from_json)\n    -   [`from_pickle`](#from_pickle)\n    -   [`from_plist`](#from_plist)\n    -   [`from_query_string`](#from_query_string)\n    -   [`from_toml`](#from_toml)\n    -   [`from_xls`](#from_xls)\n    -   [`from_xml`](#from_xml)\n    -   [`from_yaml`](#from_yaml)\n    -   [`to_base64`](#to_base64)\n    -   [`to_csv`](#to_csv)\n    -   [`to_ini`](#to_ini)\n    -   [`to_json`](#to_json)\n    -   [`to_pickle`](#to_pickle)\n    -   [`to_plist`](#to_plist)\n    -   [`to_query_string`](#to_query_string)\n    -   [`to_toml`](#to_toml)\n    -   [`to_xml`](#to_xml)\n    -   [`to_yaml`](#to_yaml)\n\n-   **Parse methods**\n\n    -   [`get_bool`](#get_bool)\n    -   [`get_bool_list`](#get_bool_list)\n    -   [`get_date`](#get_date)\n    -   [`get_date_list`](#get_date_list)\n    -   [`get_datetime`](#get_datetime)\n    -   [`get_datetime_list`](#get_datetime_list)\n    -   [`get_decimal`](#get_decimal)\n    -   [`get_decimal_list`](#get_decimal_list)\n    -   [`get_dict`](#get_dict)\n    -   [`get_email`](#get_email)\n    -   [`get_float`](#get_float)\n    -   [`get_float_list`](#get_float_list)\n    -   [`get_int`](#get_int)\n    -   [`get_int_list`](#get_int_list)\n    -   [`get_list`](#get_list)\n    -   [`get_list_item`](#get_list_item)\n    -   [`get_phonenumber`](#get_phonenumber)\n    -   [`get_slug`](#get_slug)\n    -   [`get_slug_list`](#get_slug_list)\n    -   [`get_str`](#get_str)\n    -   [`get_str_list`](#get_str_list)\n    -   [`get_uuid`](#get_uuid)\n    -   [`get_uuid_list`](#get_uuid_list)\n\n### Utility methods\n\nThese methods are common utilities that will speed up your everyday work.\n\nUtilities that accept key argument(s) also support keypath(s).\n\nUtilities that return a dictionary always return a new `benedict` instance.\n\n#### `clean`\n\n```python\n# Clean the current dict instance removing all empty values: None, \"\", {}, [], ().\n# If strings or collections (dict, list, set, tuple) flags are False,\n# related empty values will not be deleted.\nd.clean(strings=True, collections=True)\n```\n\n#### `clone`\n\n```python\n# Return a clone (deepcopy) of the dict.\nc = d.clone()\n```\n\n#### `dump`\n\n```python\n# Return a readable representation of any dict/list.\n# This method can be used both as static method or instance method.\ns = benedict.dump(d.keypaths())\nprint(s)\n# or\nd = benedict()\nprint(d.dump())\n```\n\n#### `filter`\n\n```python\n# Return a filtered dict using the given predicate function.\n# Predicate function receives key, value arguments and should return a bool value.\npredicate = lambda k, v: v is not None\nf = d.filter(predicate)\n```\n\n#### `find`\n\n```python\n# Return the first match searching for the given keys/keypaths.\n# If no result found, default value is returned.\nkeys = [\"a.b.c\", \"m.n.o\", \"x.y.z\"]\nf = d.find(keys, default=0)\n```\n\n#### `flatten`\n\n```python\n# Return a new flattened dict using the given separator to join nested dict keys to flatten keypaths.\nf = d.flatten(separator=\"_\")\n```\n\n#### `groupby`\n\n```python\n# Group a list of dicts at key by the value of the given by_key and return a new dict.\ng = d.groupby(\"cities\", by_key=\"country_code\")\n```\n\n#### `invert`\n\n```python\n# Return an inverted dict where values become keys and keys become values.\n# Since multiple keys could have the same value, each value will be a list of keys.\n# If flat is True each value will be a single value (use this only if values are unique).\ni = d.invert(flat=False)\n```\n\n#### `items_sorted_by_keys`\n\n```python\n# Return items (key/value list) sorted by keys.\n# If reverse is True, the list will be reversed.\nitems = d.items_sorted_by_keys(reverse=False)\n```\n\n#### `items_sorted_by_values`\n\n```python\n# Return items (key/value list) sorted by values.\n# If reverse is True, the list will be reversed.\nitems = d.items_sorted_by_values(reverse=False)\n```\n\n#### `keypaths`\n\n```python\n# Return a list of all keypaths in the dict.\n# If indexes is True, the output will include list values indexes.\nk = d.keypaths(indexes=False)\n```\n\n#### `match`\n\n```python\n# Return a list of all values whose keypath matches the given pattern (a regex or string).\n# If pattern is string, wildcard can be used (eg. [*] can be used to match all list indexes).\n# If indexes is True, the pattern will be matched also against list values.\nm = d.match(pattern, indexes=True)\n```\n\n#### `merge`\n\n```python\n# Merge one or more dictionary objects into current instance (deepupdate).\n# Sub-dictionaries keys will be merged together.\n# If overwrite is False, existing values will not be overwritten.\n# If concat is True, list values will be concatenated together.\nd.merge(a, b, c, overwrite=True, concat=False)\n```\n\n#### `move`\n\n```python\n# Move an item from key_src to key_dst.\n# It can be used to rename a key.\n# If key_dst exists, its value will be overwritten.\nd.move(\"a\", \"b\", overwrite=True)\n```\n\n#### `nest`\n\n```python\n# Nest a list of dicts at the given key and return a new nested list\n# using the specified keys to establish the correct items hierarchy.\nd.nest(\"values\", id_key=\"id\", parent_id_key=\"parent_id\", children_key=\"children\")\n```\n\n#### `remove`\n\n```python\n# Remove multiple keys from the dict.\n# It is possible to pass a single key or more keys (as list or *args).\nd.remove([\"firstname\", \"lastname\", \"email\"])\n```\n\n#### `rename`\n\n```python\n# Rename a dict item key from \"key\" to \"key_new\".\n# If key_new exists, a KeyError will be raised.\nd.rename(\"first_name\", \"firstname\")\n```\n\n#### `search`\n\n```python\n# Search and return a list of items (dict, key, value, ) matching the given query.\nr = d.search(\"hello\", in_keys=True, in_values=True, exact=False, case_sensitive=False)\n```\n\n#### `standardize`\n\n```python\n# Standardize all dict keys, e.g. \"Location Latitude\" -> \"location_latitude\".\nd.standardize()\n```\n\n#### `subset`\n\n```python\n# Return a dict subset for the given keys.\n# It is possible to pass a single key or more keys (as list or *args).\ns = d.subset([\"firstname\", \"lastname\", \"email\"])\n```\n\n#### `swap`\n\n```python\n# Swap items values at the given keys.\nd.swap(\"firstname\", \"lastname\")\n```\n\n#### `traverse`\n\n```python\n# Traverse a dict passing each item (dict, key, value) to the given callback function.\ndef f(d, key, value):\n    print(f\"dict: {d} - key: {key} - value: {value}\")\nd.traverse(f)\n```\n\n#### `unflatten`\n\n```python\n# Return a new unflattened dict using the given separator to split dict keys to nested keypaths.\nu = d.unflatten(separator=\"_\")\n```\n\n#### `unique`\n\n```python\n# Remove duplicated values from the dict.\nd.unique()\n```\n\n### I/O methods\n\nThese methods are available for input/output operations.\n\n#### `from_base64`\n\n```python\n# Try to load/decode a base64 encoded data and return it as benedict instance.\n# Accept as first argument: url, filepath or data-string.\n# It's possible to choose the subformat used under the hood:\n# ('csv', 'json', 'query-string', 'toml', 'xml', 'yaml'), default: 'json'.\n# It's possible to choose the encoding, default 'utf-8'.\n# A ValueError is raised in case of failure.\nd = benedict.from_base64(s, subformat=\"json\", encoding=\"utf-8\", **kwargs)\n```\n\n#### `from_cli`\n\n```python\n# Load and decode data from a string of CLI arguments.\n# ArgumentParser specific options can be passed using kwargs:\n# https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser\n# Return a new dict instance. A ValueError is raised in case of failure.\nd = benedict.from_cli(s, **kwargs)\n```\n\n#### `from_csv`\n\n```python\n# Try to load/decode a csv encoded data and return it as benedict instance.\n# Accept as first argument: url, filepath or data-string.\n# It's possible to specify the columns list, default: None (in this case the first row values will be used as keys).\n# It's possible to pass decoder specific options using kwargs:\n# https://docs.python.org/3/library/csv.html\n# A ValueError is raised in case of failure.\nd = benedict.from_csv(s, columns=None, columns_row=True, **kwargs)\n```\n\n#### `from_html`\n\n```python\n# Try to load/decode a html data and return it as benedict instance.\n# Accept as first argument: url, filepath or data-string.\n# It's possible to pass decoder specific options using kwargs:\n# https://beautiful-soup-4.readthedocs.io/\n# A ValueError is raised in case of failure.\nd = benedict.from_html(s, **kwargs)\n```\n\n#### `from_ini`\n\n```python\n# Try to load/decode a ini encoded data and return it as benedict instance.\n# Accept as first argument: url, filepath or data-string.\n# It's possible to pass decoder specific options using kwargs:\n# https://docs.python.org/3/library/configparser.html\n# A ValueError is raised in case of failure.\nd = benedict.from_ini(s, **kwargs)\n```\n\n#### `from_json`\n\n```python\n# Try to load/decode a json encoded data and return it as benedict instance.\n# Accept as first argument: url, filepath or data-string.\n# It's possible to pass decoder specific options using kwargs:\n# https://docs.python.org/3/library/json.html\n# A ValueError is raised in case of failure.\nd = benedict.from_json(s, **kwargs)\n```\n\n#### `from_pickle`\n\n```python\n# Try to load/decode a pickle encoded in Base64 format and return it as benedict instance.\n# Accept as first argument: url, filepath or data-string.\n# It's possible to pass decoder specific options using kwargs:\n# https://docs.python.org/3/library/pickle.html\n# A ValueError is raised in case of failure.\nd = benedict.from_pickle(s, **kwargs)\n```\n\n#### `from_plist`\n\n```python\n# Try to load/decode a p-list encoded data and return it as benedict instance.\n# Accept as first argument: url, filepath or data-string.\n# It's possible to pass decoder specific options using kwargs:\n# https://docs.python.org/3/library/plistlib.html\n# A ValueError is raised in case of failure.\nd = benedict.from_plist(s, **kwargs)\n```\n\n#### `from_query_string`\n\n```python\n# Try to load/decode a query-string and return it as benedict instance.\n# Accept as first argument: url, filepath or data-string.\n# A ValueError is raised in case of failure.\nd = benedict.from_query_string(s, **kwargs)\n```\n\n#### `from_toml`\n\n```python\n# Try to load/decode a toml encoded data and return it as benedict instance.\n# Accept as first argument: url, filepath or data-string.\n# It's possible to pass decoder specific options using kwargs:\n# https://pypi.org/project/toml/\n# A ValueError is raised in case of failure.\nd = benedict.from_toml(s, **kwargs)\n```\n\n#### `from_xls`\n\n```python\n# Try to load/decode a xls file (\".xls\", \".xlsx\", \".xlsm\") from url, filepath or data-string.\n# Accept as first argument: url, filepath or data-string.\n# It's possible to pass decoder specific options using kwargs:\n# - https://openpyxl.readthedocs.io/ (for .xlsx and .xlsm files)\n# - https://pypi.org/project/xlrd/ (for .xls files)\n# A ValueError is raised in case of failure.\nd = benedict.from_xls(s, sheet=0, columns=None, columns_row=True, **kwargs)\n```\n\n#### `from_xml`\n\n```python\n# Try to load/decode a xml encoded data and return it as benedict instance.\n# Accept as first argument: url, filepath or data-string.\n# It's possible to pass decoder specific options using kwargs:\n# https://github.com/martinblech/xmltodict\n# A ValueError is raised in case of failure.\nd = benedict.from_xml(s, **kwargs)\n```\n\n#### `from_yaml`\n\n```python\n# Try to load/decode a yaml encoded data and return it as benedict instance.\n# Accept as first argument: url, filepath or data-string.\n# It's possible to pass decoder specific options using kwargs:\n# https://pyyaml.org/wiki/PyYAMLDocumentation\n# A ValueError is raised in case of failure.\nd = benedict.from_yaml(s, **kwargs)\n```\n\n#### `to_base64`\n\n```python\n# Return the dict instance encoded in base64 format and optionally save it at the specified 'filepath'.\n# It's possible to choose the subformat used under the hood:\n# ('csv', json', 'query-string', 'toml', 'xml', 'yaml'), default: 'json'.\n# It's possible to choose the encoding, default 'utf-8'.\n# It's possible to pass decoder specific options using kwargs.\n# A ValueError is raised in case of failure.\ns = d.to_base64(subformat=\"json\", encoding=\"utf-8\", **kwargs)\n```\n\n#### `to_csv`\n\n```python\n# Return a list of dicts in the current dict encoded in csv format and optionally save it at the specified filepath.\n# It's possible to specify the key of the item (list of dicts) to encode, default: 'values'.\n# It's possible to specify the columns list, default: None (in this case the keys of the first item will be used).\n# A ValueError is raised in case of failure.\ns = d.to_csv(key=\"values\", columns=None, columns_row=True, **kwargs)\n```\n\n#### `to_ini`\n\n```python\n# Return the dict instance encoded in ini format and optionally save it at the specified filepath.\n# It's possible to pass encoder specific options using kwargs:\n# https://docs.python.org/3/library/configparser.html\n# A ValueError is raised in case of failure.\ns = d.to_ini(**kwargs)\n```\n\n#### `to_json`\n\n```python\n# Return the dict instance encoded in json format and optionally save it at the specified filepath.\n# It's possible to pass encoder specific options using kwargs:\n# https://docs.python.org/3/library/json.html\n# A ValueError is raised in case of failure.\ns = d.to_json(**kwargs)\n```\n\n#### `to_pickle`\n\n```python\n# Return the dict instance as pickle encoded in Base64 format and optionally save it at the specified filepath.\n# The pickle protocol used by default is 2.\n# It's possible to pass encoder specific options using kwargs:\n# https://docs.python.org/3/library/pickle.html\n# A ValueError is raised in case of failure.\ns = d.to_pickle(**kwargs)\n```\n\n#### `to_plist`\n\n```python\n# Return the dict instance encoded in p-list format and optionally save it at the specified filepath.\n# It's possible to pass encoder specific options using kwargs:\n# https://docs.python.org/3/library/plistlib.html\n# A ValueError is raised in case of failure.\ns = d.to_plist(**kwargs)\n```\n\n#### `to_query_string`\n\n```python\n# Return the dict instance as query-string and optionally save it at the specified filepath.\n# A ValueError is raised in case of failure.\ns = d.to_query_string(**kwargs)\n```\n\n#### `to_toml`\n\n```python\n# Return the dict instance encoded in toml format and optionally save it at the specified filepath.\n# It's possible to pass encoder specific options using kwargs:\n# https://pypi.org/project/toml/\n# A ValueError is raised in case of failure.\ns = d.to_toml(**kwargs)\n```\n\n#### `to_xml`\n\n```python\n# Return the dict instance encoded in xml format and optionally save it at the specified filepath.\n# It's possible to pass encoder specific options using kwargs:\n# https://github.com/martinblech/xmltodict\n# A ValueError is raised in case of failure.\ns = d.to_xml(**kwargs)\n```\n\n#### `to_yaml`\n\n```python\n# Return the dict instance encoded in yaml format.\n# If filepath option is passed the output will be saved ath\n# It's possible to pass encoder specific options using kwargs:\n# https://pyyaml.org/wiki/PyYAMLDocumentation\n# A ValueError is raised in case of failure.\ns = d.to_yaml(**kwargs)\n```\n\n### Parse methods\n\nThese methods are wrappers of the `get` method, they parse data trying to return it in the expected type.\n\n#### `get_bool`\n\n```python\n# Get value by key or keypath trying to return it as bool.\n# Values like `1`, `true`, `yes`, `on`, `ok` will be returned as `True`.\nd.get_bool(key, default=False)\n```\n\n#### `get_bool_list`\n\n```python\n# Get value by key or keypath trying to return it as list of bool values.\n# If separator is specified and value is a string it will be splitted.\nd.get_bool_list(key, default=[], separator=\",\")\n```\n\n#### `get_date`\n\n```python\n# Get value by key or keypath trying to return it as date.\n# If format is not specified it will be autodetected.\n# If choices and value is in choices return value otherwise default.\nd.get_date(key, default=None, format=None, choices=[])\n```\n\n#### `get_date_list`\n\n```python\n# Get value by key or keypath trying to return it as list of date values.\n# If separator is specified and value is a string it will be splitted.\nd.get_date_list(key, default=[], format=None, separator=\",\")\n```\n\n#### `get_datetime`\n\n```python\n# Get value by key or keypath trying to return it as datetime.\n# If format is not specified it will be autodetected.\n# If choices and value is in choices return value otherwise default.\nd.get_datetime(key, default=None, format=None, choices=[])\n```\n\n#### `get_datetime_list`\n\n```python\n# Get value by key or keypath trying to return it as list of datetime values.\n# If separator is specified and value is a string it will be splitted.\nd.get_datetime_list(key, default=[], format=None, separator=\",\")\n```\n\n#### `get_decimal`\n\n```python\n# Get value by key or keypath trying to return it as Decimal.\n# If choices and value is in choices return value otherwise default.\nd.get_decimal(key, default=Decimal(\"0.0\"), choices=[])\n```\n\n#### `get_decimal_list`\n\n```python\n# Get value by key or keypath trying to return it as list of Decimal values.\n# If separator is specified and value is a string it will be splitted.\nd.get_decimal_list(key, default=[], separator=\",\")\n```\n\n#### `get_dict`\n\n```python\n# Get value by key or keypath trying to return it as dict.\n# If value is a json string it will be automatically decoded.\nd.get_dict(key, default={})\n```\n\n#### `get_email`\n\n```python\n# Get email by key or keypath and return it.\n# If value is blacklisted it will be automatically ignored.\n# If check_blacklist is False, it will be not ignored even if blacklisted.\nd.get_email(key, default=\"\", choices=None, check_blacklist=True)\n```\n\n#### `get_float`\n\n```python\n# Get value by key or keypath trying to return it as float.\n# If choices and value is in choices return value otherwise default.\nd.get_float(key, default=0.0, choices=[])\n```\n\n#### `get_float_list`\n\n```python\n# Get value by key or keypath trying to return it as list of float values.\n# If separator is specified and value is a string it will be splitted.\nd.get_float_list(key, default=[], separator=\",\")\n```\n\n#### `get_int`\n\n```python\n# Get value by key or keypath trying to return it as int.\n# If choices and value is in choices return value otherwise default.\nd.get_int(key, default=0, choices=[])\n```\n\n#### `get_int_list`\n\n```python\n# Get value by key or keypath trying to return it as list of int values.\n# If separator is specified and value is a string it will be splitted.\nd.get_int_list(key, default=[], separator=\",\")\n```\n\n#### `get_list`\n\n```python\n# Get value by key or keypath trying to return it as list.\n# If separator is specified and value is a string it will be splitted.\nd.get_list(key, default=[], separator=\",\")\n```\n\n#### `get_list_item`\n\n```python\n# Get list by key or keypath and return value at the specified index.\n# If separator is specified and list value is a string it will be splitted.\nd.get_list_item(key, index=0, default=None, separator=\",\")\n```\n\n#### `get_phonenumber`\n\n```python\n#\u00a0Get phone number by key or keypath and return a dict with different formats (e164, international, national).\n# If country code is specified (alpha 2 code), it will be used to parse phone number correctly.\nd.get_phonenumber(key, country_code=None, default=None)\n```\n\n#### `get_slug`\n\n```python\n# Get value by key or keypath trying to return it as slug.\n# If choices and value is in choices return value otherwise default.\nd.get_slug(key, default=\"\", choices=[])\n```\n\n#### `get_slug_list`\n\n```python\n# Get value by key or keypath trying to return it as list of slug values.\n# If separator is specified and value is a string it will be splitted.\nd.get_slug_list(key, default=[], separator=\",\")\n```\n\n#### `get_str`\n\n```python\n# Get value by key or keypath trying to return it as string.\n# Encoding issues will be automatically fixed.\n# If choices and value is in choices return value otherwise default.\nd.get_str(key, default=\"\", choices=[])\n```\n\n#### `get_str_list`\n\n```python\n# Get value by key or keypath trying to return it as list of str values.\n# If separator is specified and value is a string it will be splitted.\nd.get_str_list(key, default=[], separator=\",\")\n```\n\n#### `get_uuid`\n\n```python\n# Get value by key or keypath trying to return it as valid uuid.\n# If choices and value is in choices return value otherwise default.\nd.get_uuid(key, default=\"\", choices=[])\n```\n\n#### `get_uuid_list`\n\n```python\n#\u00a0Get value by key or keypath trying to return it as list of valid uuid values.\n# If separator is specified and value is a string it will be splitted.\nd.get_uuid_list(key, default=[], separator=\",\")\n```\n\n## Testing\n```bash\n# clone repository\ngit clone https://github.com/fabiocaccamo/python-benedict.git && cd python-benedict\n\n# create virtualenv and activate it\npython -m venv venv && . venv/bin/activate\n\n# upgrade pip\npython -m pip install --upgrade pip\n\n# install requirements\npip install -r requirements.txt -r requirements-test.txt\n\n# install pre-commit to run formatters and linters\npre-commit install --install-hooks\n\n# run tests using tox\ntox\n\n# or run tests using unittest\npython -m unittest\n```\n\n## License\nReleased under [MIT License](LICENSE.txt).\n\n---\n\n## Supporting\n\n- :star: Star this project on [GitHub](https://github.com/fabiocaccamo/python-benedict)\n- :octocat: Follow me on [GitHub](https://github.com/fabiocaccamo)\n- :blue_heart: Follow me on [Twitter](https://twitter.com/fabiocaccamo)\n- :moneybag: Sponsor me on [Github](https://github.com/sponsors/fabiocaccamo)\n\n## See also\n\n- [`python-fontbro`](https://github.com/fabiocaccamo/python-fontbro) - \ud83e\udde2 friendly font operations on top of `fontTools`.\n\n- [`python-fsutil`](https://github.com/fabiocaccamo/python-fsutil) - \ud83e\udddf\u200d\u2642\ufe0f high-level file-system operations for lazy devs.\n",
    "bugtrack_url": null,
    "license": "MIT License  Copyright (c) 2019-present Fabio Caccamo  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ",
    "summary": "python-benedict is a dict subclass with keylist/keypath/keyattr support, normalized I/O operations (base64, csv, ini, json, pickle, plist, query-string, toml, xls, xml, yaml) and many utilities... for humans, obviously.",
    "version": "0.33.2",
    "project_urls": {
        "Documentation": "https://github.com/fabiocaccamo/python-benedict#readme",
        "Download": "https://github.com/fabiocaccamo/python-benedict/releases",
        "Funding": "https://github.com/sponsors/fabiocaccamo/",
        "Homepage": "https://github.com/fabiocaccamo/python-benedict",
        "Issues": "https://github.com/fabiocaccamo/python-benedict/issues",
        "Twitter": "https://twitter.com/fabiocaccamo"
    },
    "split_keywords": [
        "python",
        "dictionary",
        "dictionaries",
        "dict",
        "benedict",
        "subclass",
        "extended",
        "keylist",
        "keypath",
        "utility",
        "io",
        "data",
        "file",
        "url",
        "read",
        "write",
        "parse",
        "configparser",
        "config",
        "cfg",
        "pickle",
        "plist",
        "base64",
        "csv",
        "html",
        "ini",
        "json",
        "query-string",
        "toml",
        "xml",
        "yaml",
        "clean",
        "clone",
        "deepclone",
        "deepupdate",
        "dump",
        "filter",
        "flatten",
        "groupby",
        "invert",
        "merge",
        "move",
        "nest",
        "remove",
        "rename",
        "search",
        "standardize",
        "subset",
        "swap",
        "traverse",
        "unflatten",
        "unique"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "685fe32644b743d33142c6c43af50c86c6a5f535c3b3fa5b50c92aecded37741",
                "md5": "7a2f38ec63765ea9cc3dfe6ee624ea00",
                "sha256": "50a69b601b34d4ad7b67fe94e3266ec05046bc547a4132fe43fd8fbd41aeefaa"
            },
            "downloads": -1,
            "filename": "python_benedict-0.33.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "7a2f38ec63765ea9cc3dfe6ee624ea00",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 51285,
            "upload_time": "2024-03-04T23:25:39",
            "upload_time_iso_8601": "2024-03-04T23:25:39.899287Z",
            "url": "https://files.pythonhosted.org/packages/68/5f/e32644b743d33142c6c43af50c86c6a5f535c3b3fa5b50c92aecded37741/python_benedict-0.33.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "5763a3d1de78d75b28e9105c236565b9f0366e009abb489a5acb09911fcf5768",
                "md5": "b52bf18924e9a3754ba873476558729e",
                "sha256": "662de43bffb4e127da2056447f8ddd7f6f5c89b72dd66d289cf9abd1cc2720c8"
            },
            "downloads": -1,
            "filename": "python-benedict-0.33.2.tar.gz",
            "has_sig": false,
            "md5_digest": "b52bf18924e9a3754ba873476558729e",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 53224,
            "upload_time": "2024-03-04T23:25:42",
            "upload_time_iso_8601": "2024-03-04T23:25:42.408811Z",
            "url": "https://files.pythonhosted.org/packages/57/63/a3d1de78d75b28e9105c236565b9f0366e009abb489a5acb09911fcf5768/python-benedict-0.33.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-03-04 23:25:42",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "fabiocaccamo",
    "github_project": "python-benedict#readme",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [],
    "tox": true,
    "lcname": "python-benedict"
}
        
Elapsed time: 0.20511s