Usage#
To use dotwiz
in a project:
from dotwiz import *
Default for Missing Keys#
The default behavior for DotWiz
or DotWizPlus
is
to raise an AttributeError
if an attribute (key) doesn’t exist:
>>> from dotwiz import DotWiz
>>> DotWiz(key='test').other_key
Traceback (most recent call last):
AttributeError: 'DotWiz' object has no attribute 'other_key'
The helper function set_default_for_missing_keys
can be used
to return a default value for any missing attributes, as shown (or None
if the argument is omitted).
This essentially implements a custom __getattr__
on the public, exported classes.
from dotwiz import DotWiz, DotWizPlus, set_default_for_missing_keys
# if omitted, the default value is `None`
set_default_for_missing_keys('test')
dw = DotWiz(hello='world!')
assert dw.hello == 'world!'
assert dw.world == 'test'
assert DotWizPlus().missing_key == 'test'
DotWizPlus
#
Simple usage with DotWizPlus
to illustrate how keys with invalid characters
are made safe for attribute access:
from dotwiz import DotWizPlus
dw = DotWizPlus({
'items': {
'camelCase': 1,
'TitleCase': 2,
'Spinal-Case': 3,
'To': {'1NFINITY': {'AND': {'Beyond !! ': True}}},
'1abc': 4,
'42': 5,
'Hello !@#&^+ W0rld !!!': 'test',
}
})
print(dw)
# prints the following, on a single line:
# > ✪(items_=✪(camel_case=1, title_case=2, spinal_case=3,
# to=✪(_1nfinity=✪(and_=✪(beyond=True))),
# _1abc=4, _42=5, hello_w0rld='test'))
# confirm that we can access keys by dot (.) notation
assert dw.items_.to._1nfinity.and_.beyond
assert dw.items_._1abc == 4
# the original keys can also be accessed like a normal `dict`, if needed
assert dw['items']['To']['1NFINITY']['AND']['Beyond !! ']
print(dw.to_dict())
# > {'items': {'camelCase': 1, 'TitleCase': 2, ...}}
print(dw.to_attr_dict())
# > {'items_': {'camel_case': 1, 'title_case': 2, ...}}
Complete Example#
Example with make_dot_wiz_plus
to illustrate how DotWizPlus
mutates keys with invalid characters to a safe, snake-cased format:
from dotwiz import make_dot_wiz_plus
dw = make_dot_wiz_plus(
[
# 1: reserved `keywords`
('class', 1), ('for', 1), ('lambda', 1), ('pass', 1),
# 2: overwriting `dict` or `DotWizPlus` method names
('to_dict', 2), ('items', 2), ('keys', 2), ('copy', 2), ('values', 2),
# 3: invalid identifiers
('99', 3), ('1abc', 3), ('x+y', 3),
('This @!@# I!@#$%^&*()[]{};:"\'<,>.?/s a test.', 3),
('Hello !@#&^+ W0rld !!!', 3),
# 4: special-cased keys
('Title Case', 4), ('SCREAMING_SNAKE_CASE', 4),
('camelCase', 4), ('PascalCase', 4), ('spinal-case', 4),
],
)
print(dw)
# prints the following, on a single line:
# > ✪(class_=1, for_=1, lambda_=1, pass_=1,
# to_dict_=2, items_=2, keys_=2, copy_=2, values_=2,
# _99=3, _1abc=3, x_y=3, this_i_s_a_test=3, hello_w0rld=3,
# title_case=4, screaming_snake_case=4, camel_case=4, pascal_case=4, spinal_case=4)
print(dw.to_dict())
# > {'class': 1, 'for': 1, ...}
print(dw.to_attr_dict())
# > {'class_': 1, 'for_': 1, ...}
# confirm that retrieving keys from the `DotWizPlus` instance by
# attribute (dot) access works as expected.
assert dw.class_ == dw.for_ == dw.lambda_ == dw.pass_ == 1
assert dw.to_dict_ == dw.items_ == dw.keys_ == dw.copy_ == dw.values_ == 2
assert dw._99 == dw._1abc == dw.x_y == dw.this_i_s_a_test == dw.hello_w0rld == 3
assert dw.title_case == dw.screaming_snake_case == \
dw.camel_case == dw.pascal_case == dw.spinal_case == 4