extradict


Nameextradict JSON
Version 0.6.0 PyPI version JSON
download
home_pagehttps://github.com/jsbueno/extradict
SummaryEnhanced, maybe useful, data containers and utilities: A versioned dictionary, a bidirectional dictionary, a binary tree backed dictionary, a Grouper iterator mapper similar to itertools.tee, and an easy extractor from dictionary key/values to variables
upload_time2022-05-19 02:28:19
maintainer
docs_urlNone
authorJoão S. O. Bueno
requires_python>=3.6
licenseLGPLv3+
keywords versioned bijective assigner getter unpack transactional container collection dict dictionary normalized binarytree
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Extra Dictionary classes and utilities for Python

Some Mapping containers and tools for daily use with Python.
This attempts to be a small package with no dependencies,
just delivering its data-types as described bellow
enough tested for production-usage.


## VersionDict

A Python Mutable Mapping Container (dictionary :-) ) that
can "remember" previous values.
Use it wherever you would use a dict - at each
key change or update, it's `version` attribute
is increased by one.

### Special and modified methods:

`.get` method is modified to receive an optional
named  `version` parameter that allows one to retrieve
for a key the value it contained at that respective version.
NB. When using the `version` parameter, `get` will raise
a KeyError if the key does not exist for that version and
no default value is specified.

`.copy(version=None)`:  yields a copy of the current dictionary at that version, with history preserved
(if version is not given, the current version is used)

`.freeze(version=None)` yields a snapshot of the versionDict in the form of a plain dictionary for
the specified version


### Implementation:
It works by internally keeping a list of (named)tuples with
(version, value) for each key.


### Example:

```python

>>> from extradict import VersionDict
>>> a = VersionDict(b=0)
>>> a["b"] = 1
>>> a["b"]
1
>>> a.get("b", version=0)
0
```

For extra examples, check the "tests" directory

## OrderedVersionDict

Inherits from VersionDict, but preserves and retrieves key
insertion order. Unlike a plain "collections.OrderedDict",
however, whenever a key's value is updated, it is moved
last on the dictionary order.

### Example:
```python
>>> from collections import OrderedDict
>>> a = OrderedDict((("a", 1), ("b", 2), ("c", 3)))
>>> list(a.keys())
>>> ['a', 'b', 'c']
>>> a["a"] = 3
>>> list(a.keys())
>>> ['a', 'b', 'c']

>>> from extradict import OrderedVersionDict
>>> a = OrderedVersionDict((("a", 1), ("b", 2), ("c", 3)))
>>> list(a.keys())
['a', 'b', 'c']
>>> a["a"] = 3
>>> list(a.keys())
['b', 'c', 'a']
```

## MapGetter
A Context manager that allows one to pick variables from inside a dictionary,
mapping, or any Python object by using the  `from <myobject> import key1, key2` statement.



```python
>>> from extradict import MapGetter
>>> a = dict(b="test", c="another test")
>>> with MapGetter(a) as a:
...     from a import b, c
...
>>> print (b, c)
test another test
```

Or:
```python
>>> from collections import namedtuple
>>> a = namedtuple("a", "c d")
>>> b = a(2,3)
>>> with MapGetter(b):
...     from b import c, d
>>> print(c, d)
2, 3
```

It works with Python 3.4+ "enum"s - which is great as it allow one
to use the enums by their own name, without having to prepend the Enum class
every time:
```python
>>> from enum import Enum

>>> class Colors(tuple, Enum):
...     red = 255, 0, 0
...     green = 0, 255, 0
...     blue = 0, 0, 255
...

>>> with MapGetter(Colors):
...    from Colors import red, green, blue
...

>>> red
<Colors.red: (255, 0, 0)>
>>> red[0]
255
```

MapGetter can also have a `default` value or callable which
will generate values for each name that one tries to "import" from it:

```python
>>> with MapGetter(default=lambda x: x) as x:
...    from x import foo, bar, baz
...

>>> foo
'foo'
>>> bar
'bar'
>>> baz
'baz'
```

If the parameter default is not a callable, it is assigned directly to
the imported names. If it is a callable, MapGetter will try to call it passing
each name as the first and only positional parameter. If that fails
with a type error, it calls it without parameters the way collections.defaultdict
works.


The syntax `from <mydict> import key1 as var1` works as well.

## BijectiveDict
This is a bijective dictionary for which each pair key, value added
is also added as value, key.

The explicitly inserted keys can be retrieved as the "assigned_keys"
attribute - and a dictionary copy with all such keys is available
at the "BijectiveDict.assigned".
Conversely, the generated keys are exposed as "BijectiveDict.generated_keys"
and can be seen as a dict at "Bijective.generated"

```python
>>> from extradict import BijectiveDict
>>>
>>> a = BijectiveDict(b = 1, c = 2)
>>> a
BijectiveDict({'b': 1, 2: 'c', 'c': 2, 1: 'b'})
>>> a[2]
'c'
>>> a[2] = "d"
>>> a["d"]
2
>>> a["c"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/gwidion/projetos/extradict/extradict/reciprocal_dict.py", line 31, in __getitem__
    return self._data[item]
KeyError: 'c'
>>>
```

## namedtuple
Alternate, clean room, implementation of 'namedtuple' as in stdlib's collection.namedtuple
. This does not make use of "eval" at runtime - and can be up to 10 times faster to create
a namedtuple class than the stdlib version.

Instead, it relies on closures to do its magic.

However, these will be slower to instantiate than stdlib version. The "fastnamedtuple"
is faster in all respects, although it holds the same API for instantiating as tuples, and
performs no length checking.


## fastnamedtuple
Like namedtuple but the class returned take an iterable for its values
rather than positioned or named parameters. No checks are made towards the iterable
length, which should match the number of attributes
It is faster for instantiating as compared with stdlib's namedtuple


## defaultnamedtuple
Implementation of named-tuple using default parameters -
Either pass a sequence of 2-tuples (or an OrderedDict) as the second parameter, or
send in kwargs with the default parameters, after the first.
(This takes advantage of python3.6 + guaranteed ordering of **kwargs for a function
see https://docs.python.org/3.6/whatsnew/3.6.html)

The resulting object can accept positional or named parameters to be instantiated, as a
normal namedtuple, however, any omitted parameters are used from the original
mapping passed to it.


## FallbackNormalizedDict
Dictionary meant for text only keys:
will normalize keys in a way that capitalization, whitespace and
punctuation will be ignored when retrieving items.

A parallel dictionary is maintained with the original keys,
so that strings that would clash on normalization can still
be used as separated key/value pairs if original punctuation
is passed in the key.

Primary use case if for keeping translation strings when the source
for the original strings is loose in terms of whitespace/punctuation
(for example, in an http snippet)


## NormalizedDict
Dictionary meant for text only keys:
will normalize keys in a way that capitalization, whitespace and
punctuation will be ignored when retrieving items.

Unlike FallbackNormalizedDict this does not keep the original
version of the keys.


## TreeDict
A Python mapping with an underlying auto-balancing binary tree data structure.
As such, it allows seeking ranges of keys - so, that
`mytreedict["aa":"bz"] will return a list with all values in
the dictionary whose keys are strings starting from "aa"
up to those starting with "by".

It also features a `.get_closest_keys` method that will
retrieve the closest existing keys for the required element.
```python
>>> from extradict import TreeDict
>>> a = TreeDict()
>>> a[1] = "one word"
>>> a[3] = "another word"
>>> a[:]
['one word', 'another word']
>>> a.get_closest_keys(2)
(1, 3)
```

Another feature of these dicts is that as they
do not rely on an object hash, any Python
object can be used as a key. Of course
key objects should be comparable with <=, ==, >=. If
they are not, errors will be raised. HOWEVER, there is
an extra feature - when creating the TreeDict a named
argument `key` parameter can be passed that works the
same as Python's `sorted` "key" parameter: a callable
that will receive the key/value pair as its sole argument
and should return a comparable object. The returned object
is the one used to keep the Binary Tree organized.


If the output of the given `key_func` ties, that is it:
the new pair simply overwrites whatever other key/value
had the same key_func output. To avoid that,
craft the key_funcs so that they return a tuple
with the original key as the second item:
```python
>>> from extradict import TreeDict
>>> b = TreeDict(key=len)
>>> b["red"] = 1
>>> b["blue"] = 2
>>> b
TreeDict('red'=1, 'blue'=2, key_func= <built-in function len>)

>>> b["1234"] = 5
>>> b
TreeDict('red'=1, '1234'=5, key_func= <built-in function len>)

>>> TreeDict(key=lambda k: (len(k), k))
>>> b["red"] = 1
>>> b["blue"] = 2
>>> b["1234"] = 5
>>> b
>>> TreeDict('red'=1, '1234'=5, 'blue'=2, key_func= <function <lambda> at 0x7fbc7f462320>)
```

### PlainNode and AVLNode

To support the TreeDict mapping interface, the standalone
`PlainNode` and `AVLNode` classes are available at
the `extradict.binary_tree_dict` module - and can be used
to create a lower level tree data structure, which can
have more capabilities. For one, the "raw" use allows
repeated values in the Nodes, all Nodes are root to
their own subtrees and know nothing of their parents,
and if one wishes, no need to work with "key: value" pairs:
if a "pair" argument is not supplied to a Node, it
reflects the given Key as its own value.

`PlainNode` will build non-autobalancing trees,
while those built with `AVLNode` will be self-balancing.
Trying to manually mix node types in the same tree, or
changing the key_func in different notes,
will obviously wreck everything.

## Grouper


Think of it as an itertools.groupby which returns a mapping
Or as an itertools.tee that splits the stream into filtered
substreams according to the passed key-callable.

Given an iterable and a key callable,
each element in the iterable is run through the key callable and
made available in an iterator under a bucket using the resulting key-value.

The source iterable need not be ordered (unlike itertools.groupby).
If no key function  is given, the identity function is used.

The items will be made available under the iterable-values as requested,
in a lazy way when possible. Note that several different method calls may
precipatate an eager processing of all items in the source iterator:
.keys() or len(), for example.

Whenever a new key is found during input consumption, a "Queue" iterator,
which is a thin wrapper over collections.deque is created under that key
and can be further iterated to retrieve more elements that map to
the same key.

In short, this is very similar to `itertools.tee`, but with a filter
so that each element goes to a mapped bucket.

Once created, the resulting object may obtionally be called. Doing this
will consume all data in the source iterator at once, and return a
a plain dictionary with all data fetched into lists.

For example, to divide a sequence of numbers from 0 to 10 in
5 buckets, all one need to do is: `Grouper(myseq, lambda x: x // 2)`

Or:
```python
>>> from extradict import Grouper
>>> even_odd = Grouper(range(10), lambda x: "even" if not x % 2 else "odd")
>>> print(list(even_odd["even"]))
[0, 2, 4, 6, 8]
>>> print(list(even_odd["odd"]))
[1, 3, 5, 7, 9]

```


## NestedData

Nestable mappings and sequences data structure to facilitate field access

The idea is a single data structure that can hold "JSON" data, adding some
helper methods and functionalities.

Primarily, one can use a dotted string path to access a deply nested key, value pair,
instead of concatenating several dictionary ".get" calls.

Examples:
      `person["address.city"] instead of person["address"]["city"]`

      or

      `persons["10.contacts.emails.0"]`


The first tool available is the ability to merge mappings with extra keys
into existing nested mappings, without deleting non colidng keys:
a "person.address" key that would contain "city" but no "street" or "zip-code"
can be updated with:  `record["person"].merge({"address": {"street": "5th ave", "zip-code": "000000"}})`
preserving the "person.address.city" value in the process.

The ".data" attribute stores the object contents as a tree of dicionary and lists as needed -
these are lazily wrapped as NestedData instances if retrieved through the class, but
can be freely manipulated directly.

```python
>>> import json
>>> from extradict import NestedData
>>> a = NestedData(json.load(open("myfile.json")))
>>> assert a["persons.0.address"] == a["persons"][0]["address"]
True
>>> a.merge({"city": None}, "persons.*.address")  # creates a new "city" key in all addresses
```
            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/jsbueno/extradict",
    "name": "extradict",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.6",
    "maintainer_email": "",
    "keywords": "versioned bijective assigner getter unpack transactional container collection dict dictionary normalized binarytree",
    "author": "Jo\u00e3o S. O. Bueno",
    "author_email": "gwidion@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/c9/a0/7fd85f23867457de4debd927721926cb239046e1dc83b23b5cab155602ed/extradict-0.6.0.tar.gz",
    "platform": null,
    "description": "# Extra Dictionary classes and utilities for Python\n\nSome Mapping containers and tools for daily use with Python.\nThis attempts to be a small package with no dependencies,\njust delivering its data-types as described bellow\nenough tested for production-usage.\n\n\n## VersionDict\n\nA Python Mutable Mapping Container (dictionary :-) ) that\ncan \"remember\" previous values.\nUse it wherever you would use a dict - at each\nkey change or update, it's `version` attribute\nis increased by one.\n\n### Special and modified methods:\n\n`.get` method is modified to receive an optional\nnamed  `version` parameter that allows one to retrieve\nfor a key the value it contained at that respective version.\nNB. When using the `version` parameter, `get` will raise\na KeyError if the key does not exist for that version and\nno default value is specified.\n\n`.copy(version=None)`:  yields a copy of the current dictionary at that version, with history preserved\n(if version is not given, the current version is used)\n\n`.freeze(version=None)` yields a snapshot of the versionDict in the form of a plain dictionary for\nthe specified version\n\n\n### Implementation:\nIt works by internally keeping a list of (named)tuples with\n(version, value) for each key.\n\n\n### Example:\n\n```python\n\n>>> from extradict import VersionDict\n>>> a = VersionDict(b=0)\n>>> a[\"b\"] = 1\n>>> a[\"b\"]\n1\n>>> a.get(\"b\", version=0)\n0\n```\n\nFor extra examples, check the \"tests\" directory\n\n## OrderedVersionDict\n\nInherits from VersionDict, but preserves and retrieves key\ninsertion order. Unlike a plain \"collections.OrderedDict\",\nhowever, whenever a key's value is updated, it is moved\nlast on the dictionary order.\n\n### Example:\n```python\n>>> from collections import OrderedDict\n>>> a = OrderedDict(((\"a\", 1), (\"b\", 2), (\"c\", 3)))\n>>> list(a.keys())\n>>> ['a', 'b', 'c']\n>>> a[\"a\"] = 3\n>>> list(a.keys())\n>>> ['a', 'b', 'c']\n\n>>> from extradict import OrderedVersionDict\n>>> a = OrderedVersionDict(((\"a\", 1), (\"b\", 2), (\"c\", 3)))\n>>> list(a.keys())\n['a', 'b', 'c']\n>>> a[\"a\"] = 3\n>>> list(a.keys())\n['b', 'c', 'a']\n```\n\n## MapGetter\nA Context manager that allows one to pick variables from inside a dictionary,\nmapping, or any Python object by using the  `from <myobject> import key1, key2` statement.\n\n\n\n```python\n>>> from extradict import MapGetter\n>>> a = dict(b=\"test\", c=\"another test\")\n>>> with MapGetter(a) as a:\n...     from a import b, c\n...\n>>> print (b, c)\ntest another test\n```\n\nOr:\n```python\n>>> from collections import namedtuple\n>>> a = namedtuple(\"a\", \"c d\")\n>>> b = a(2,3)\n>>> with MapGetter(b):\n...     from b import c, d\n>>> print(c, d)\n2, 3\n```\n\nIt works with Python 3.4+ \"enum\"s - which is great as it allow one\nto use the enums by their own name, without having to prepend the Enum class\nevery time:\n```python\n>>> from enum import Enum\n\n>>> class Colors(tuple, Enum):\n...     red = 255, 0, 0\n...     green = 0, 255, 0\n...     blue = 0, 0, 255\n...\n\n>>> with MapGetter(Colors):\n...    from Colors import red, green, blue\n...\n\n>>> red\n<Colors.red: (255, 0, 0)>\n>>> red[0]\n255\n```\n\nMapGetter can also have a `default` value or callable which\nwill generate values for each name that one tries to \"import\" from it:\n\n```python\n>>> with MapGetter(default=lambda x: x) as x:\n...    from x import foo, bar, baz\n...\n\n>>> foo\n'foo'\n>>> bar\n'bar'\n>>> baz\n'baz'\n```\n\nIf the parameter default is not a callable, it is assigned directly to\nthe imported names. If it is a callable, MapGetter will try to call it passing\neach name as the first and only positional parameter. If that fails\nwith a type error, it calls it without parameters the way collections.defaultdict\nworks.\n\n\nThe syntax `from <mydict> import key1 as var1` works as well.\n\n## BijectiveDict\nThis is a bijective dictionary for which each pair key, value added\nis also added as value, key.\n\nThe explicitly inserted keys can be retrieved as the \"assigned_keys\"\nattribute - and a dictionary copy with all such keys is available\nat the \"BijectiveDict.assigned\".\nConversely, the generated keys are exposed as \"BijectiveDict.generated_keys\"\nand can be seen as a dict at \"Bijective.generated\"\n\n```python\n>>> from extradict import BijectiveDict\n>>>\n>>> a = BijectiveDict(b = 1, c = 2)\n>>> a\nBijectiveDict({'b': 1, 2: 'c', 'c': 2, 1: 'b'})\n>>> a[2]\n'c'\n>>> a[2] = \"d\"\n>>> a[\"d\"]\n2\n>>> a[\"c\"]\nTraceback (most recent call last):\n  File \"<stdin>\", line 1, in <module>\n  File \"/home/gwidion/projetos/extradict/extradict/reciprocal_dict.py\", line 31, in __getitem__\n    return self._data[item]\nKeyError: 'c'\n>>>\n```\n\n## namedtuple\nAlternate, clean room, implementation of 'namedtuple' as in stdlib's collection.namedtuple\n. This does not make use of \"eval\" at runtime - and can be up to 10 times faster to create\na namedtuple class than the stdlib version.\n\nInstead, it relies on closures to do its magic.\n\nHowever, these will be slower to instantiate than stdlib version. The \"fastnamedtuple\"\nis faster in all respects, although it holds the same API for instantiating as tuples, and\nperforms no length checking.\n\n\n## fastnamedtuple\nLike namedtuple but the class returned take an iterable for its values\nrather than positioned or named parameters. No checks are made towards the iterable\nlength, which should match the number of attributes\nIt is faster for instantiating as compared with stdlib's namedtuple\n\n\n## defaultnamedtuple\nImplementation of named-tuple using default parameters -\nEither pass a sequence of 2-tuples (or an OrderedDict) as the second parameter, or\nsend in kwargs with the default parameters, after the first.\n(This takes advantage of python3.6 + guaranteed ordering of **kwargs for a function\nsee https://docs.python.org/3.6/whatsnew/3.6.html)\n\nThe resulting object can accept positional or named parameters to be instantiated, as a\nnormal namedtuple, however, any omitted parameters are used from the original\nmapping passed to it.\n\n\n## FallbackNormalizedDict\nDictionary meant for text only keys:\nwill normalize keys in a way that capitalization, whitespace and\npunctuation will be ignored when retrieving items.\n\nA parallel dictionary is maintained with the original keys,\nso that strings that would clash on normalization can still\nbe used as separated key/value pairs if original punctuation\nis passed in the key.\n\nPrimary use case if for keeping translation strings when the source\nfor the original strings is loose in terms of whitespace/punctuation\n(for example, in an http snippet)\n\n\n## NormalizedDict\nDictionary meant for text only keys:\nwill normalize keys in a way that capitalization, whitespace and\npunctuation will be ignored when retrieving items.\n\nUnlike FallbackNormalizedDict this does not keep the original\nversion of the keys.\n\n\n## TreeDict\nA Python mapping with an underlying auto-balancing binary tree data structure.\nAs such, it allows seeking ranges of keys - so, that\n`mytreedict[\"aa\":\"bz\"] will return a list with all values in\nthe dictionary whose keys are strings starting from \"aa\"\nup to those starting with \"by\".\n\nIt also features a `.get_closest_keys` method that will\nretrieve the closest existing keys for the required element.\n```python\n>>> from extradict import TreeDict\n>>> a = TreeDict()\n>>> a[1] = \"one word\"\n>>> a[3] = \"another word\"\n>>> a[:]\n['one word', 'another word']\n>>> a.get_closest_keys(2)\n(1, 3)\n```\n\nAnother feature of these dicts is that as they\ndo not rely on an object hash, any Python\nobject can be used as a key. Of course\nkey objects should be comparable with <=, ==, >=. If\nthey are not, errors will be raised. HOWEVER, there is\nan extra feature - when creating the TreeDict a named\nargument `key` parameter can be passed that works the\nsame as Python's `sorted` \"key\" parameter: a callable\nthat will receive the key/value pair as its sole argument\nand should return a comparable object. The returned object\nis the one used to keep the Binary Tree organized.\n\n\nIf the output of the given `key_func` ties, that is it:\nthe new pair simply overwrites whatever other key/value\nhad the same key_func output. To avoid that,\ncraft the key_funcs so that they return a tuple\nwith the original key as the second item:\n```python\n>>> from extradict import TreeDict\n>>> b = TreeDict(key=len)\n>>> b[\"red\"] = 1\n>>> b[\"blue\"] = 2\n>>> b\nTreeDict('red'=1, 'blue'=2, key_func= <built-in function len>)\n\n>>> b[\"1234\"] = 5\n>>> b\nTreeDict('red'=1, '1234'=5, key_func= <built-in function len>)\n\n>>> TreeDict(key=lambda k: (len(k), k))\n>>> b[\"red\"] = 1\n>>> b[\"blue\"] = 2\n>>> b[\"1234\"] = 5\n>>> b\n>>> TreeDict('red'=1, '1234'=5, 'blue'=2, key_func= <function <lambda> at 0x7fbc7f462320>)\n```\n\n### PlainNode and AVLNode\n\nTo support the TreeDict mapping interface, the standalone\n`PlainNode` and `AVLNode` classes are available at\nthe `extradict.binary_tree_dict` module - and can be used\nto create a lower level tree data structure, which can\nhave more capabilities. For one, the \"raw\" use allows\nrepeated values in the Nodes, all Nodes are root to\ntheir own subtrees and know nothing of their parents,\nand if one wishes, no need to work with \"key: value\" pairs:\nif a \"pair\" argument is not supplied to a Node, it\nreflects the given Key as its own value.\n\n`PlainNode` will build non-autobalancing trees,\nwhile those built with `AVLNode` will be self-balancing.\nTrying to manually mix node types in the same tree, or\nchanging the key_func in different notes,\nwill obviously wreck everything.\n\n## Grouper\n\n\nThink of it as an itertools.groupby which returns a mapping\nOr as an itertools.tee that splits the stream into filtered\nsubstreams according to the passed key-callable.\n\nGiven an iterable and a key callable,\neach element in the iterable is run through the key callable and\nmade available in an iterator under a bucket using the resulting key-value.\n\nThe source iterable need not be ordered (unlike itertools.groupby).\nIf no key function  is given, the identity function is used.\n\nThe items will be made available under the iterable-values as requested,\nin a lazy way when possible. Note that several different method calls may\nprecipatate an eager processing of all items in the source iterator:\n.keys() or len(), for example.\n\nWhenever a new key is found during input consumption, a \"Queue\" iterator,\nwhich is a thin wrapper over collections.deque is created under that key\nand can be further iterated to retrieve more elements that map to\nthe same key.\n\nIn short, this is very similar to `itertools.tee`, but with a filter\nso that each element goes to a mapped bucket.\n\nOnce created, the resulting object may obtionally be called. Doing this\nwill consume all data in the source iterator at once, and return a\na plain dictionary with all data fetched into lists.\n\nFor example, to divide a sequence of numbers from 0 to 10 in\n5 buckets, all one need to do is: `Grouper(myseq, lambda x: x // 2)`\n\nOr:\n```python\n>>> from extradict import Grouper\n>>> even_odd = Grouper(range(10), lambda x: \"even\" if not x % 2 else \"odd\")\n>>> print(list(even_odd[\"even\"]))\n[0, 2, 4, 6, 8]\n>>> print(list(even_odd[\"odd\"]))\n[1, 3, 5, 7, 9]\n\n```\n\n\n## NestedData\n\nNestable mappings and sequences data structure to facilitate field access\n\nThe idea is a single data structure that can hold \"JSON\" data, adding some\nhelper methods and functionalities.\n\nPrimarily, one can use a dotted string path to access a deply nested key, value pair,\ninstead of concatenating several dictionary \".get\" calls.\n\nExamples:\n      `person[\"address.city\"] instead of person[\"address\"][\"city\"]`\n\n      or\n\n      `persons[\"10.contacts.emails.0\"]`\n\n\nThe first tool available is the ability to merge mappings with extra keys\ninto existing nested mappings, without deleting non colidng keys:\na \"person.address\" key that would contain \"city\" but no \"street\" or \"zip-code\"\ncan be updated with:  `record[\"person\"].merge({\"address\": {\"street\": \"5th ave\", \"zip-code\": \"000000\"}})`\npreserving the \"person.address.city\" value in the process.\n\nThe \".data\" attribute stores the object contents as a tree of dicionary and lists as needed -\nthese are lazily wrapped as NestedData instances if retrieved through the class, but\ncan be freely manipulated directly.\n\n```python\n>>> import json\n>>> from extradict import NestedData\n>>> a = NestedData(json.load(open(\"myfile.json\")))\n>>> assert a[\"persons.0.address\"] == a[\"persons\"][0][\"address\"]\nTrue\n>>> a.merge({\"city\": None}, \"persons.*.address\")  # creates a new \"city\" key in all addresses\n```",
    "bugtrack_url": null,
    "license": "LGPLv3+",
    "summary": "Enhanced, maybe useful, data containers and utilities: A versioned dictionary, a bidirectional dictionary, a binary tree backed dictionary, a Grouper iterator mapper similar to itertools.tee, and an easy extractor from dictionary key/values to variables",
    "version": "0.6.0",
    "project_urls": {
        "Homepage": "https://github.com/jsbueno/extradict"
    },
    "split_keywords": [
        "versioned",
        "bijective",
        "assigner",
        "getter",
        "unpack",
        "transactional",
        "container",
        "collection",
        "dict",
        "dictionary",
        "normalized",
        "binarytree"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "c9a07fd85f23867457de4debd927721926cb239046e1dc83b23b5cab155602ed",
                "md5": "389409ab7b666e5d00e0c648324d94d0",
                "sha256": "4c937436fe993282bc8ef1bed5824f51627c7f9765a2f874c72d5abe1082ace2"
            },
            "downloads": -1,
            "filename": "extradict-0.6.0.tar.gz",
            "has_sig": false,
            "md5_digest": "389409ab7b666e5d00e0c648324d94d0",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.6",
            "size": 126499,
            "upload_time": "2022-05-19T02:28:19",
            "upload_time_iso_8601": "2022-05-19T02:28:19.870986Z",
            "url": "https://files.pythonhosted.org/packages/c9/a0/7fd85f23867457de4debd927721926cb239046e1dc83b23b5cab155602ed/extradict-0.6.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2022-05-19 02:28:19",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "jsbueno",
    "github_project": "extradict",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "extradict"
}
        
Elapsed time: 0.06464s