dendrodict 1.0.4
Dict type that makes it easier to work with deeply nested dicts.
License: MIT

==========
dendrodict
==========

Dictionary types that make it easier to work trees of nested dictionaries.

Consider a nested regular dictionaries::

  d = {
      "en": {
          "gb": "English (United Kingdom)",
          "us": "English (United States)",
          "ca": "English (Canada)",
          "za": "English (South Africa)",
      },
      "no": {
          "nb": "Norwegian (Bokmål)",
          "nn": "Norwegian (Nynorsk)",
      },
      "fr": {
          "be": "French (Belgium)",
          "ca": "French (Canada)",
          "fr": "French (Standard)",
          "ch": "French (Switzerland)",
      }
  }

from which we can construct a ``DeepDict``::

  >>> from dendrodict import DeepDict
  >>> languages = DeepDict(d)

Nested dictionaries can be accessed with single application of the square brackets get-item
operator::

  >>> languages["fr", "ca"]
  'French (Canada)'

or by using a tuple as a key::

  >>> languages[("no", "nb")]
  'Norwegian (Bokmål)'

The tuple key can also be used with other dictionary methods, such as ``get()``::

  >>> languages.get(("en", "us"))
  'English (United States)'

It's still possible index the inner dictionary levels::

  >>> languages["en"]
  DeepDict(
      {
          'gb': 'English (United Kingdom)',
          'us': 'English (United States)',
          'ca': 'English (Canada)',
          'za': 'English (South Africa)'
      }
  )

which means that separate lookup operations are still supported::

  >>> languages["en"]["za"]
  'English (South Africa)'


The tuple key form can also be used on construction, so flat dictionaries with tuple keys will be
expanded into nested dictionaries. Consider the following single-level mapping of tuple keys to
values::

  blocks = {
      ("mineral", "sandstone", "block"): "Sandstone",
      ("mineral", "sandstone", "chiseled"): "Sandstone (Chiseled)",
      ("mineral", "cobblestone", "block"): "Cobblestone",
      ("mineral", "cobblestone", "slab"): "Cobblestone (Slab)",
      ("mineral", "gold", "ore"): "Gold Ore",
      ("wood", "birch", "block"): "Birch",
      ("wood", "birch", "slab"): "Birch-Wood Slab",
      ("wood", "oak", "block"): "Oak",
      ("wood", "oak", "plank"): "Wooden Plank (Oak)",
  }

Created a ``DeepDict`` from this, gives a three-level structure::

  >>> minecraft = DeepDict(blocks)

which we can see by converted back to dictionaries using the ``to_dict()`` method::

  >>> minecraft.to_dict()
  {'mineral': {
      'cobblestone': {
          'block': 'Cobblestone',
          'slab': 'Cobblestone (Slab)'
      },
      'gold': {
          'ore': 'Gold Ore'
      },
      'sandstone': {
          'block': 'Sandstone',
          'chiseled': 'Sandstone (Chiseled)'
      }
  },
  'wood': {
      'birch': {
          'block': 'Birch',
          'slab': 'Birch-Wood Slab'
      },
      'oak': {
          'block': 'Oak',
          'plank': 'Wooden Plank (Oak)'}
      }
  }


Particularly when dealing with configuration data, it can be useful to be able to use dotted names
for access to nested items. Use ``DottedDeepDict`` for this::

  from dendrodict import DottedDeepDict

  displays = DottedDeepDict(
      {
          "resolution": {
              "vga": {
                  "width": 640,
                  "height": 480,
              },
              "wxga": {
                  "width": 1280,
                  "height": 800,
              },
              "wqhd": {
                  "width": 2560,
                  "height": 1440,
              },
          }
      }
  )

Dotted name syntax can be used for lookup::

  >>> displays["resolution.vga.width"]
  640

or for assignment at arbitrary levels::

  >>> displays["resolution.1080p.width"] = 1920
  >>> displays["resolution.1080p.height"] = 1080

Shallower levels are still available individually::

  >>> displays["resolution.1080p"]
  DottedDeepDict({'width': 1920, 'height': 1080})

and can be converted back to regular dictionaries::

  >>> displays["resolution.wqhd"].to_dict()
  {'width': 2560, 'height': 1440}