Skip to content

Commit 4ad8947

Browse files
add rudimentary getting started guide from slack thread
1 parent 52b0030 commit 4ad8947

File tree

3 files changed

+318
-1
lines changed

3 files changed

+318
-1
lines changed

docs/source/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ TBD.
1111
:maxdepth: 2
1212

1313
api_reference/index
14-
14+
tutorials/index
Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
.. _getting_started_tutorial:
2+
3+
===============
4+
Getting Started
5+
===============
6+
7+
.. todo
8+
MIC-6169. Below is a copy/paste from a slack thread that should be revised and
9+
improved upon.
10+
11+
To highlight how ``.get()`` works, let's make a two-layer tree of cats and their colors.
12+
13+
.. code-block:: python
14+
15+
from layered_config_tree import LayeredConfigTree
16+
tree = LayeredConfigTree(layers=["base", "override"])
17+
18+
# Add whipper with the incorrect color to the base layer
19+
tree.update({"pet": {"cat": {"whipper": "black"}}}, layer="base")
20+
21+
# Update whipper's color and add burt mackling to the override layer
22+
tree.update({"pet": {"cat": {"whipper": "gray", "burt_macklin": "tuxedo"}}}, layer="override")
23+
24+
tree
25+
26+
::
27+
28+
pet:
29+
cat:
30+
whipper:
31+
override: gray
32+
source: None
33+
base: black
34+
source: None
35+
burt_macklin:
36+
override: tuxedo
37+
source: None
38+
39+
.. testcode::
40+
:hide:
41+
42+
from layered_config_tree import LayeredConfigTree
43+
44+
tree = LayeredConfigTree(layers=["base", "override"])
45+
tree.update({"pet": {"cat": {"whipper": "black"}}}, layer="base")
46+
tree.update({"pet": {"cat": {"whipper": "gray", "burt_macklin": "tuxedo"}}}, layer="override")
47+
print(tree)
48+
49+
.. testoutput::
50+
51+
pet:
52+
cat:
53+
whipper:
54+
override: gray
55+
burt_macklin:
56+
override: tuxedo
57+
58+
We can chain ``.get()`` calls to retrieve sub-trees.
59+
60+
.. code-block:: python
61+
62+
tree.get("pet").get("cat")
63+
64+
::
65+
66+
whipper:
67+
override: gray
68+
source: None
69+
base: black
70+
source: None
71+
burt_macklin:
72+
override: tuxedo
73+
source: None
74+
75+
Even better, we can pass a list to ``.get()`` to retrieve nested sub-trees in one call.
76+
77+
.. code-block:: python
78+
79+
tree.get(["pet", "cat"])
80+
81+
::
82+
83+
whipper:
84+
override: gray
85+
source: None
86+
base: black
87+
source: None
88+
burt_macklin:
89+
override: tuxedo
90+
source: None
91+
92+
This also works for ``.get_tree()``.
93+
94+
.. code-block:: python
95+
96+
tree.get_tree(["pet", "cat"])
97+
98+
::
99+
100+
whipper:
101+
override: gray
102+
source: None
103+
base: black
104+
source: None
105+
burt_macklin:
106+
override: tuxedo
107+
source: None
108+
109+
.. testcode::
110+
:hide:
111+
112+
print(tree.get("pet").get("cat"))
113+
print(tree.get(["pet", "cat"]))
114+
print(tree.get_tree(["pet", "cat"]))
115+
116+
.. testoutput::
117+
118+
whipper:
119+
override: gray
120+
burt_macklin:
121+
override: tuxedo
122+
whipper:
123+
override: gray
124+
burt_macklin:
125+
override: tuxedo
126+
whipper:
127+
override: gray
128+
burt_macklin:
129+
override: tuxedo
130+
131+
Note that calling ``get_tree()`` will raise an error if the thing being returned
132+
isn't actually a tree.
133+
134+
.. code-block:: python
135+
136+
tree.get_tree(["pet", "cat", "whipper"])
137+
138+
::
139+
140+
Traceback (most recent call last):
141+
File "<stdin>", line 1, in <module>
142+
File "/mnt/share/homes/sbachmei/repos/layered_config_tree/src/layered_config_tree/main.py", line 451, in get_tree
143+
raise ConfigurationError(
144+
layered_config_tree.exceptions.ConfigurationError: The data you accessed using ['pet', 'cat', 'whipper'] with get_tree was of type <class 'str'>, but get_tree must return a LayeredConfigTree.
145+
146+
``get()`` is designed to work like dict.get(), i.e. it will return a default
147+
(None by default) if the value doesn't exist.
148+
149+
.. code-block:: python
150+
151+
# get burt_macklin's color
152+
tree.get(["pet", "cat", "burt_macklin"], default_value="oops")
153+
# get garfield's color - but garfield doesn't exist
154+
tree.get(["pet", "cat", "garfield"], default_value="oops")
155+
156+
::
157+
158+
tuxedo
159+
oops
160+
161+
This works when trying to return a sub-tree as well.
162+
163+
.. code-block:: python
164+
165+
# get the entire cat tree (hah)
166+
tree.get(["pet", "cat"], default_value="oops")
167+
# get the non-existing dog tree
168+
tree.get(["pet", "dog"], default_value="oops")
169+
170+
::
171+
172+
whipper:
173+
override: gray
174+
source: None
175+
base: black
176+
source: None
177+
burt_macklin:
178+
override: tuxedo
179+
source: None
180+
oops
181+
182+
.. testcode::
183+
:hide:
184+
185+
print(tree.get(["pet", "cat", "burt_macklin"], default_value="oops"))
186+
print(tree.get(["pet", "cat", "garfield"], default_value="oops"))
187+
print(tree.get(["pet", "cat"], default_value="oops"))
188+
print(tree.get(["pet", "dog"], default_value="oops"))
189+
190+
.. testoutput::
191+
192+
tuxedo
193+
oops
194+
whipper:
195+
override: gray
196+
burt_macklin:
197+
override: tuxedo
198+
oops
199+
200+
Also note that ``.get_tree()`` does *not* have this functionality, i.e. there is
201+
no default_value arg to that method!
202+
203+
You can also request a specific layer from the tree using the ``layer`` argument.
204+
205+
.. code-block:: python
206+
207+
# get whipper's color from the default layer (outermost)
208+
tree.get(["pet", "cat", "whipper"])
209+
# get whipper's color from the base layer
210+
tree.get(["pet", "cat", "whipper"], layer="base")
211+
212+
::
213+
214+
gray
215+
black
216+
217+
.. testcode::
218+
:hide:
219+
220+
print(tree.get(["pet", "cat", "whipper"]))
221+
print(tree.get(["pet", "cat", "whipper"], layer="base"))
222+
223+
.. testoutput::
224+
225+
gray
226+
black
227+
228+
Note that this call will raise if the layer doesn't actually exist for a given
229+
sub-tree. For example, we are able to retrieve Whipper's color at the "base" layer:
230+
231+
.. code-block:: python
232+
233+
tree.get(["pet", "cat", "whipper"], layer="base")
234+
235+
::
236+
237+
gray
238+
239+
But trying to get Burt Macklin's color at the "base" layer will raise an error
240+
since that layer doesn't exist for him:
241+
242+
.. code-block:: python
243+
244+
tree.get(["pet", "cat", "burt_macklin"], layer="base")
245+
246+
::
247+
248+
Traceback (most recent call last):
249+
File "<stdin>", line 1, in <module>
250+
File "/mnt/share/homes/sbachmei/repos/layered_config_tree/src/layered_config_tree/main.py", line 412, in get
251+
return tree.get(final_key, default_value=default_value, layer=layer)
252+
File "/mnt/share/homes/sbachmei/repos/layered_config_tree/src/layered_config_tree/main.py", line 406, in get
253+
return child.get_value(layer=layer)
254+
File "/mnt/share/homes/sbachmei/repos/layered_config_tree/src/layered_config_tree/main.py", line 135, in get_value
255+
value = self._get_value_with_source(layer)[1]
256+
File "/mnt/share/homes/sbachmei/repos/layered_config_tree/src/layered_config_tree/main.py", line 220, in _get_value_with_source
257+
raise MissingLayerError(
258+
layered_config_tree.exceptions.MissingLayerError: No value stored in this ConfigNode cat at layer base.
259+
260+
One final note. The interaction between default_value and layer may sometimes be
261+
a cause of confusion. The default_value will only be returned when also providing
262+
a specific layer iff the requested value doesn't exist at all. If the value does
263+
exist, just not at the requested layer, then you'll get the MissingLayerError.
264+
265+
For example, let's get Garfield's color at the "base" layer (noting that Garfield
266+
does not exist in the tree) and provide a default return value of "foo":
267+
268+
.. code-block:: python
269+
270+
tree.get(["pet", "cat", "garfield"], default_value="foo", layer="base")
271+
272+
::
273+
274+
foo
275+
276+
.. testcode::
277+
:hide:
278+
279+
print(tree.get(["pet", "cat", "garfield"], default_value="foo", layer="base"))
280+
281+
.. testoutput::
282+
283+
foo
284+
285+
Now let's do the same thing for Burt Macklin (who *does* exist in the tree but does
286+
not have a "base" layer defined):
287+
288+
.. code-block:: python
289+
290+
tree.get(["pet", "cat", "burt_macklin"], default_value="foo", layer="base")
291+
292+
::
293+
294+
Traceback (most recent call last):
295+
File "<stdin>", line 1, in <module>
296+
File "/mnt/share/homes/sbachmei/repos/layered_config_tree/src/layered_config_tree/main.py", line 412, in get
297+
return tree.get(final_key, default_value=default_value, layer=layer)
298+
File "/mnt/share/homes/sbachmei/repos/layered_config_tree/src/layered_config_tree/main.py", line 406, in get
299+
return child.get_value(layer=layer)
300+
File "/mnt/share/homes/sbachmei/repos/layered_config_tree/src/layered_config_tree/main.py", line 135, in get_value
301+
value = self._get_value_with_source(layer)[1]
302+
File "/mnt/share/homes/sbachmei/repos/layered_config_tree/src/layered_config_tree/main.py", line 220, in _get_value_with_source
303+
raise MissingLayerError(
304+
layered_config_tree.exceptions.MissingLayerError: No value stored in this ConfigNode cat at layer base.
305+

docs/source/tutorials/index.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.. _tutorial_main:
2+
3+
=========
4+
Tutorials
5+
=========
6+
Here you'll find a set of tutorials to introduce you to layered config trees
7+
8+
.. toctree::
9+
:maxdepth: 2
10+
:glob:
11+
12+
*

0 commit comments

Comments
 (0)