nadict¶
A nested dict with both attribute and item access.
NA stands for Nested and Attribute.
NADict
¶
A nested dict with both attribute and item access.
It is intended to be used with keys that are valid Python identifiers. However, except for string keys containing a dot, there are actually no hard limitations. If a key equals an existing attribute name, attribute access is of cause not possible.
Nested items can be accessed via a dot notation, as shown in the example below.
Examples¶
n = NADict(a=1, b=NADict(c=3, d=4)) n['a'] 1 n.a 1 n['b.c'] 3 n.b.c 3 n['b.e'] = 5 n.b.e 5
Attributes¶
_dict : dict Dictionary holding the actial items.
Source code in ontopy/nadict.py
class NADict:
"""A nested dict with both attribute and item access.
It is intended to be used with keys that are valid Python
identifiers. However, except for string keys containing a dot,
there are actually no hard limitations. If a key equals an existing
attribute name, attribute access is of cause not possible.
Nested items can be accessed via a dot notation, as shown in the
example below.
Examples
--------
>>> n = NADict(a=1, b=NADict(c=3, d=4))
>>> n['a']
1
>>> n.a
1
>>> n['b.c']
3
>>> n.b.c
3
>>> n['b.e'] = 5
>>> n.b.e
5
Attributes
----------
_dict : dict
Dictionary holding the actial items.
"""
def __init__(self, *args, **kw):
object.__setattr__(self, "_dict", {})
self.update(*args, **kw)
def __getitem__(self, key):
if "." in key:
key1, key2 = key.split(".", 1)
return self._dict[key1][key2]
return self._dict[key]
def __setitem__(self, key, value):
if key in (
"clear",
"copy",
"fromkeys",
"get",
"items",
"keys",
"pop",
"popitem",
"setdefault",
"update",
"values",
):
raise ValueError(
f"invalid key {key!r}: must not override supported dict method"
" names"
)
if "." in key:
key1, key2 = key.split(".", 1)
if key1 not in self._dict:
self._dict[key1] = NADict()
self._dict[key1][key2] = value
elif key in self._dict:
if isinstance(self._dict[key], NADict):
self._dict[key].update(value)
else:
self._dict[key] = value
else:
if isinstance(value, Mapping):
self._dict[key] = NADict(value)
else:
self._dict[key] = value
def __delitem__(self, key):
if "." in key:
key1, key2 = key.split(".", 1)
del self._dict[key1][key2]
else:
del self._dict[key]
def __getattr__(self, key):
if key not in self._dict:
raise AttributeError(f"No such key: {key}")
return self._dict[key]
def __setattr__(self, key, value):
if key in self._dict:
self._dict[key] = value
else:
object.__setattr__(self, key, value)
def __delattr__(self, key):
if key in self._dict:
del self._dict[key]
else:
object.__delattr__(self, key)
def __len__(self):
return len(self._dict)
def __contains__(self, key):
if "." in key:
key1, key2 = key.split(".", 1)
return key2 in self._dict[key1]
return key in self._dict
def __iter__(self, prefix=""):
for key, value in self._dict.items():
key = f"{prefix}.{key}" if prefix else key
if isinstance(value, NADict):
yield from value.__iter__(key)
else:
yield key
def __repr__(self):
return (
f"{self.__class__.__name__}("
f"{', '.join(f'{key}={value!r}' for key, value in self._dict.items())})" # pylint: disable=line-too-long
)
def clear(self):
"""Clear all keys."""
self._dict.clear()
def copy(self):
"""Returns a deep copy of self."""
return copy.deepcopy(self)
@staticmethod
def fromkeys(iterable, value=None):
"""Returns a new NADict with keys from `iterable` and values
set to `value`."""
res = NADict()
for key in iterable:
res[key] = value
return res
def get(self, key, default=None):
"""Returns the value for `key` if `key` is in self, else return
`default`."""
if "." in key:
key1, key2 = key.split(".", 1)
return self._dict[key1].get(key2, default)
return self._dict.get(key, default)
def items(self, prefix=""):
"""Returns an iterator over all items as (key, value) pairs."""
for key, value in self._dict.items():
key = f"{prefix}.{key}" if prefix else key
if isinstance(value, NADict):
yield from value.items(key)
else:
yield (key, value)
def keys(self, prefix=""):
"""Returns an iterator over all keys."""
for key, value in self._dict.items():
key = f"{prefix}.{key}" if prefix else key
if isinstance(value, NADict):
yield from value.keys(key)
else:
yield key
def pop(self, key, default=None):
"""Removed `key` and returns corresponding value. If `key` is not
found, `default` is returned if given, otherwise KeyError is
raised."""
if "." in key:
key1, key2 = key.split(".", 1)
return self._dict[key1].pop(key2, default)
return self._dict.pop(key, default)
def popitem(self, prefix=""):
"""Removes and returns some (key, value). Raises KeyError if empty."""
item = self._dict.popitem()
if isinstance(item, NADict):
key, value = item
item2 = item.popitem(key)
self._dict[key] = value
return item2
key, value = self._dict.popitem()
key = f"{prefix}.{key}" if prefix else key
return (key, value)
def setdefault(self, key, value=None):
"""Inserts `key` and `value` pair if key is not found.
Returns the new value for `key`."""
if "." in key:
key1, key2 = key.split(".", 1)
return self._dict[key1].setdefault(key2, value)
return self._dict.setdefault(key, value)
def update(self, *args, **kwargs):
"""Updates self with dict/iterable from `args` and keyword arguments
from `kw`."""
for arg in args:
if hasattr(arg, "keys"):
for _ in arg:
self[_] = arg[_]
else:
for key, value in arg:
self[key] = value
for key, value in kwargs.items():
self[key] = value
def values(self):
"""Returns a set-like providing a view of all style values."""
return self._dict.values()
clear(self)
¶
Clear all keys.
Source code in ontopy/nadict.py
def clear(self):
"""Clear all keys."""
self._dict.clear()
copy(self)
¶
Returns a deep copy of self.
Source code in ontopy/nadict.py
def copy(self):
"""Returns a deep copy of self."""
return copy.deepcopy(self)
fromkeys(iterable, value=None)
staticmethod
¶
Returns a new NADict with keys from iterable
and values
set to value
.
Source code in ontopy/nadict.py
@staticmethod
def fromkeys(iterable, value=None):
"""Returns a new NADict with keys from `iterable` and values
set to `value`."""
res = NADict()
for key in iterable:
res[key] = value
return res
get(self, key, default=None)
¶
Returns the value for key
if key
is in self, else return
default
.
Source code in ontopy/nadict.py
def get(self, key, default=None):
"""Returns the value for `key` if `key` is in self, else return
`default`."""
if "." in key:
key1, key2 = key.split(".", 1)
return self._dict[key1].get(key2, default)
return self._dict.get(key, default)
items(self, prefix='')
¶
Returns an iterator over all items as (key, value) pairs.
Source code in ontopy/nadict.py
def items(self, prefix=""):
"""Returns an iterator over all items as (key, value) pairs."""
for key, value in self._dict.items():
key = f"{prefix}.{key}" if prefix else key
if isinstance(value, NADict):
yield from value.items(key)
else:
yield (key, value)
keys(self, prefix='')
¶
Returns an iterator over all keys.
Source code in ontopy/nadict.py
def keys(self, prefix=""):
"""Returns an iterator over all keys."""
for key, value in self._dict.items():
key = f"{prefix}.{key}" if prefix else key
if isinstance(value, NADict):
yield from value.keys(key)
else:
yield key
pop(self, key, default=None)
¶
Removed key
and returns corresponding value. If key
is not
found, default
is returned if given, otherwise KeyError is
raised.
Source code in ontopy/nadict.py
def pop(self, key, default=None):
"""Removed `key` and returns corresponding value. If `key` is not
found, `default` is returned if given, otherwise KeyError is
raised."""
if "." in key:
key1, key2 = key.split(".", 1)
return self._dict[key1].pop(key2, default)
return self._dict.pop(key, default)
popitem(self, prefix='')
¶
Removes and returns some (key, value). Raises KeyError if empty.
Source code in ontopy/nadict.py
def popitem(self, prefix=""):
"""Removes and returns some (key, value). Raises KeyError if empty."""
item = self._dict.popitem()
if isinstance(item, NADict):
key, value = item
item2 = item.popitem(key)
self._dict[key] = value
return item2
key, value = self._dict.popitem()
key = f"{prefix}.{key}" if prefix else key
return (key, value)
setdefault(self, key, value=None)
¶
Inserts key
and value
pair if key is not found.
Returns the new value for key
.
Source code in ontopy/nadict.py
def setdefault(self, key, value=None):
"""Inserts `key` and `value` pair if key is not found.
Returns the new value for `key`."""
if "." in key:
key1, key2 = key.split(".", 1)
return self._dict[key1].setdefault(key2, value)
return self._dict.setdefault(key, value)
update(self, *args, **kwargs)
¶
Updates self with dict/iterable from args
and keyword arguments
from kw
.
Source code in ontopy/nadict.py
def update(self, *args, **kwargs):
"""Updates self with dict/iterable from `args` and keyword arguments
from `kw`."""
for arg in args:
if hasattr(arg, "keys"):
for _ in arg:
self[_] = arg[_]
else:
for key, value in arg:
self[key] = value
for key, value in kwargs.items():
self[key] = value
values(self)
¶
Returns a set-like providing a view of all style values.
Source code in ontopy/nadict.py
def values(self):
"""Returns a set-like providing a view of all style values."""
return self._dict.values()